iOSにおけるマルチスレッドを実装して確認してみる


iOSにおけるマルチスレッドの概念について、
理解を深めるために実際に動きで確認できるよう実装してみました。

#### マルチスレッドについて

- マルチスレッドとは並行処理のことである
- スレッドには、メインスレッドとバックグラウンドスレッドの二種類がある
- メインスレッドはUI更新時に、バックグラウンドスレッドは通信などUI以外の処理に使用される

iOSでは、主に***GCD(Grand Central Dispatch)***を用いて、タスクをクロージャで渡す。

##### なぜマルチスレッドが必要か？
- 通信処理時には待ち時間が発生する
- この処理をメインスレッドで行うと、画面描画やユーザーからのアクションにも待ちが生じる
- iPhone自体の処理能力は非常に高いので、CPUを有効活用する必要がある

##### GCD を用いた並行処理
- メインスレッド

```swift

DispatchQueue.main.async {
// UI更新処理
}
```
- バックグランド

```swift
DispatchQueue.global.async {
// バックグランド処理
}
```
以下で、Web API のリクエストを行い、結果をUIに表示させるだけの簡単な実装を行います。

viewdidloadで呼ばれた"ロード中"の表示は、メインスレッドで呼ばれます。
その時、非同期のバックグラウンドスレッドでは通信が行われています。
そして通信が終了したところで、レスポンス結果を受け取ります。それをUIに反映させるのはメインスレッドで行うため、DispatchQueue.main.asyncで記述します。

- 使用API - [Discogs API](https://www.discogs.com/developers/)

ドキュメントの中に、
> To browse different pages, or change the number of items per page (up to 100), use the page and per_page query string parameters:
(別のページを参照したり、1ページあたりのアイテム数を変更したりするには（最大100個まで）、pageとper_pageクエリ文字列パラメータを使用します。)

とあるので、例として以下の様にURLを組み立てます。

```swift
let page = "2"
let per_page = "5"

let urlString = "https://api.discogs.com/artists/1/releases?page=\(page)&per_page=\(per_page)"
```
これを使って、ViewControllerだけでマルチスレッドの処理を確認します。

```swift
class ViewController: UIViewController {
    
    var label: UITextView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        label = UITextView()
        label.text = "ロード中"
        label.frame = CGRect(x: 10, y: 30, width: self.view.frame.width - 20, height: 300)
        self.view.addSubview(label)
        
        let page = "2"
        let per_page = "5"
        
        let urlString = "https://api.discogs.com/artists/1/releases?page=\(page)&per_page=\(per_page)"
        
        let url = URL(string: urlString)!
        var request = URLRequest(url: url)
        request.httpMethod = "GET"
        
        let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
            
            guard let data = data else { return }
            
            do {
                let object = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
                DispatchQueue.main.async { // UI更新の処理
                    self.label.text = object?.description
                    self.label.sizeToFit()
                }
            } catch let e {
                print(e)
            }
        }
        task.resume()
 
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
}
```

繰り返しになりますが、上記のHTTP通信処理はバックグラウンドスレッドで行われています。
一方で、UI更新の DispatchQueue.main.async の処理は、メインスレッドで行われます。

![イメージ 5.GIF](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464115/4bf4377d-cadb-e68e-06ca-16f89ff1c2b0.gif)

"ロード中"が表示され、その後通信結果が表示されることが確認できました。

## 参考文献

- [iOSアプリ開発デザインパターン入門](https://www.amazon.co.jp/iOS%E3%82%A2%E3%83%97%E3%83%AA%E9%96%8B%E7%99%BA%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E5%85%A5%E9%96%80-%E6%8A%80%E8%A1%93%E6%9B%B8%E5%85%B8%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA%EF%BC%88NextPublishing%EF%BC%89-%E5%8D%83%E8%91%89-%E5%A4%A7%E5%BF%97-ebook/dp/B07DKT9YZX)