iOSにおけるマルチスレッドの概念について、
理解を深めるために実際に動きで確認できるよう実装してみました。
マルチスレッドについて
- マルチスレッドとは並行処理のことである
- スレッドには、メインスレッドとバックグラウンドスレッドの二種類がある
- メインスレッドはUI更新時に、バックグラウンドスレッドは通信などUI以外の処理に使用される
iOSでは、主に***GCD(Grand Central Dispatch)***を用いて、タスクをクロージャで渡す。
なぜマルチスレッドが必要か?
- 通信処理時には待ち時間が発生する
- この処理をメインスレッドで行うと、画面描画やユーザーからのアクションにも待ちが生じる
- iPhone自体の処理能力は非常に高いので、CPUを有効活用する必要がある
GCD を用いた並行処理
- メインスレッド
DispatchQueue.main.async {
// UI更新処理
}
- バックグランド
DispatchQueue.global.async {
// バックグランド処理
}
以下で、Web API のリクエストを行い、結果をUIに表示させるだけの簡単な実装を行います。
viewdidloadで呼ばれた"ロード中"の表示は、メインスレッドで呼ばれます。
その時、非同期のバックグラウンドスレッドでは通信が行われています。
そして通信が終了したところで、レスポンス結果を受け取ります。それをUIに反映させるのはメインスレッドで行うため、DispatchQueue.main.asyncで記述します。
- 使用API - Discogs API
ドキュメントの中に、
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を組み立てます。
let page = "2"
let per_page = "5"
let urlString = "https://api.discogs.com/artists/1/releases?page=\(page)&per_page=\(per_page)"
これを使って、ViewControllerだけでマルチスレッドの処理を確認します。
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 の処理は、メインスレッドで行われます。
"ロード中"が表示され、その後通信結果が表示されることが確認できました。