忘備録-iOSの通信できるアプリ

趣味でiOSアプリ開発をかじっていた自分が、改めてiOS開発を勉強し始めた際に、曖昧に理解していたところや知らなかったところをメモしています。いつか書き直します。

## 参考文献

この記事は以下の書籍の情報を参考にして執筆しました。

- [本気ではじめるiPhoneアプリ作り Xcode 10.x対応 (Informatics&IDEA)](https://www.amazon.co.jp/%E6%9C%AC%E6%B0%97%E3%81%A7%E3%81%AF%E3%81%98%E3%82%81%E3%82%8BiPhone%E3%82%A2%E3%83%97%E3%83%AA%E4%BD%9C%E3%82%8A-Xcode-10-x%E5%AF%BE%E5%BF%9C-Informatics-IDEA/dp/4815600031/)


##メイン実行ループとスレッドの基本

##イベント処理の概要図

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542614/ecf8074a-9a11-28ec-85b4-c0b2d5a8a5df.png)

##メインスレッドとワーカースレッド
メインキュー : イベントキューの中のUIの操作や更新を行うためのキュー。
メインスレッド : メインキューからイベントを取り出して処理をするスレッド。

メイン処理で時間がかかる処理を行うと、そのUIの更新処理がされないためアプリがフリーズして見える。


ワーカスレッド : 時間がかかる処理を行う用のスレッド。メインキューとは別のスレッドを持つ。UIの更新はできない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542614/c8dcf530-fb4a-7e55-06ac-a3b9a382eef8.png)


##通信を行うサンプルコード
gooラボ様の[ひらがな化API](https://labs.goo.ne.jp/api/jp/hiragana-translation/)を叩くサンプル。
入力した文字列の読み方を表示する。

![APIsample.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542614/1e144b7c-d5c2-c5fe-55d5-c544dd501887.gif)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542614/6f653903-ff7d-3346-4d92-2161d502ca17.png)


storyboard
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542614/04452638-64e3-22ae-bdc0-0de3e73b8b39.png)

```swift
import UIKit

class ViewController: UIViewController {
  
  @IBOutlet weak var resultDisplay: UITextView!
  @IBOutlet weak var textField: UITextField!
  override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
  }
  
  @IBAction func tapButton(_ sender: Any) {
    if let text = textField.text {
      hiraganaConversion(sentence: text)
    }
  }
  
  func hiraganaConversion(sentence: String) {
    let url = URL(string: "https://labs.goo.ne.jp/api/hiragana")
    guard let requestUrl = url else { return }
    
    let httpBody = getHttpBody(sentence: sentence, outPutType: "hiragana")
    let postUrl = createPostUrl(requestUrl: requestUrl, httpBody: httpBody)
    postRequest(request: postUrl)
  }
  
  func getHttpBody(sentence: String, outPutType: String) -> String{
    let appId = ****API_Keyを入力してください*****
    let outPutType = outPutType
    return "app_id=\(appId)&sentence=\(sentence)&output_type=\(outPutType)"
  }
  
  func createPostUrl(requestUrl: URL, httpBody: String) -> URLRequest {
    var request = URLRequest(url: requestUrl)
    request.httpMethod = "POST"
    request.httpBody = httpBody.data(using: .utf8)
    return request
  }
  
  func postRequest(request: URLRequest){
    let session = URLSession.shared
    let task = session.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
      // 通信終了後の処理
      
      // エラーの場合、本当はちゃんとエラー表示とかするべき
      guard error == nil else { return }
      guard let data = data else { return }
      do {
        let decoder = JSONDecoder()
        // ここでスネークケースの変数名をキャメルケースに置き換えている
        decoder.keyDecodingStrategy = .convertFromSnakeCase
        let result = try decoder.decode(ResultSet.self, from: data)
        print(result.converted)
        // ラベルに描画する処理を実施。ここでメインキューにイベントを渡す
        DispatchQueue.main.async {
          self.resultDisplay.text = result.converted
        }
      } catch {
        print("error")
      }
    }
    // 通信開始
    task.resume()
  }

}

class ResultSet: Codable {
  let converted: String
  let outputType: String
  let requestId: String
//  // スネークケースの変数名をキャメルケースに置き換える方法その２
//  private enum CodingKeys: String, CodingKey{
//    case converted
//    case outputType = "output_type"
//    case requestId = "request_id"
//  }
}

```