Swift3からAPIを叩いてJSONの値を取得する

iPhoneアプリ作成の勉強中、ボタンをタップして文字列を表示するという例題があったので
APIを叩いてJSONで値をもらって表示できるかな?と思いトライした記録です。
超初心者の写経中の遊び心という脱線の記録とも言います。


## 勉強の元ネタ
* 絶対に挫折しないiPhoneアプリ開発「超」入門 増補改訂第5版 Swift3&iOS 10.1移行完全対応
	* P.148　UI部品の配置にあるHelloというアプリ


## 元ネタから改造した点
* Before
	* ボタンをタップするとLabelに予め設定したテキストが表示されるのみ

* After1
	* ボタンを2つ配置し、タップするボタンに応じ予め設定したテキストが表示されるように改造

	> アクションの内容としては
	>	* 1つ目は、任意の文字列を表示させる
	>	* 2つ目は、起動時に表示される文字列を表示させる
	> といった感じ。

* After2 ← 今ココ
	* 1つ目をタップすると"inet-ip.info/json"にhttp接続しグローバルIPとISPのFQDNを取得、表示する。
	* 2つ目をタップすると、起動時に表示される文字列を表示する。

## 注意点
1. XCodeのデフォルト設定ではhttps通信しか許可されないようで、以下の対処が必要でした。
	* Project内のinfo.plistにApp Transport Security Settingsを追加
	* App Transport Security Settings配下に、Allow Arbitrary Loadsを追加し値を”YES”に変更

2. 後述の参考URLの記事をベースに実装していましたが、取得した値を表示する処理をメインスレッドで行わない場合、どうも処理落ちしているっぽいことが判明しました。
> DispatchQueue.main.asyncというのを使って、メインスレッドで表示させることで解消。レスポンスもUPし(ﾟдﾟ)ｳﾏｰな感じ。がしましたが気のせいだったかも。。。

3. inet-ip.infoは、GETメソッドでアクセスする必要がありました。(後述のコード参照)

## 汚いソースのお披露目
書籍と参考URLをベースに実装した結果がコチラ

```Swift:ViewController.swift

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var label: UILabel!
    @IBAction func getNwinfo() {
        // 取得したJSONを格納する変数を定義
        var getJson: NSDictionary!
        
        // 抽出した"ip"を格納する変数を定義
        var jsonIp = ""
        
        // 抽出した"hostname"を格納する変数を定義
        var jsonHostname = ""

        // 抽出した"ip"と"hostname"を結合する変数を定義
        var jsonString = ""
        
        // API接続先
        let urlStr = "http://inet-ip.info/json"
        
        if let url = URL(string: urlStr) {
            let req = NSMutableURLRequest(url: url)
            req.httpMethod = "GET"
            // req.httpBody = "userId=\(self.userId)&code=\(self.code)".data(using: String.Encoding.utf8)
            let task = URLSession.shared.dataTask(with: req as URLRequest, completionHandler: { (data, resp, err) in
                print(resp!.url!)
                print(NSString(data: data!, encoding: String.Encoding.utf8.rawValue) as Any)
                
                // 受け取ったdataをJSONパース、エラーならcatchへジャンプ
                do {
                    // dataをJSONパースし、変数"getJson"に格納
                    getJson = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSDictionary
                    
                    jsonIp = (getJson["IP"] as? String)!
                    jsonHostname = (getJson["Hostname"] as? String)!
                    jsonString = "m9(・∀・)NW情報ゲトしますた！\n\nGlobalIP : " + jsonIp + "\nISP FQDN : " + jsonHostname
 
                    print (jsonIp)
                    print (jsonHostname)

                    DispatchQueue.main.async{
                        self.label.text = jsonString
                    }
                } catch {
                    print ("json error")
                    return
                }
            })
            task.resume()
        }
    }
    @IBAction func goBack() {
        label.text = "(๑•̀ㅁ•́๑)✧シャキーン"
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}
```


## 参考URL
* [[swift3.0系]POSTでAPI（PHP）からJSONを取得し、パースする方法](http://swift-labo.net/2017/01/30/192/)
* [inet-ip.info](https://inet-ip.info)


## Special Thanks
[@Ryuichirou](http://qiita.com/Ryuichirou)