LoginSignup
46
44

More than 5 years have passed since last update.

NSOperationQueueを使って、安心・安全にマルチスレッド処理を行う

Posted at

この記事はiOS Advent Calendar 2014の25日目の記事です。
※今回の記事を読む前に昨日のAndroidの記事を読むことをお勧めします。

12月もとうとう25日ですね!
本日はみなさん共通の知り合いの誕生日ですね。お祝いですね。

そんな共通の知人へのお祝いを二人でどうぞしてください。
※共通の知人:キリスト


では、本題に入りましょう。今回はスレッド周りの話をします。

【何故、クリスマスにスレッドの話】

そりゃもう、マルチスレッドを巧みに扱う人はこんな大切な日でもマルチスレッド並みにN股くらい仕掛けているんだろうなぁ。という話ですよ。

さらにはスレッドセーフなので、同時刻に複数人と会っても彼氏・彼女達に感づられることも無いのでしょうね。素晴らしい。

さて、そんなシングルスレッド。いや、ゼロスレッドの画面の前のみなさんも、マルチスレッドの扱いに長けることさえできれば来年は明るいクリスマス(イブ)が待っていますよ。(スレッドセーフでお願いします)

さてさて、話を戻しましょう。
スレッドは理解している人からすると、簡単に扱えるし効率的に使用することができます。
しかし、初心者の方(特にクリスマスに予定がない方)からすると「スレッド 扱い わからない [検索]」はあるあるだと思うのでそういった方向けです。

ちなみに、このくだりは昨日のAndroid Advent Calendar 2014の記事で使っています。


UIのカクツキ、A・N・R!

皆さんはアプリを作っていているとUIのカクツキにいつかはぶち当たるでしょう。

そして突然の……

_人人人人人人人人_
>  クラッシュ!  <
 ̄YYYYYYYY ̄

NSOperationクラス

「自前で実装している処理が重い!」

そんなときのケアは自分で行わないといけません。

重い処理をNSOperationを継承した別クラスにあるオーバーライドしたmainメソッドに定義します。

そのクラスのインスタンスを生成し、別スレッドに渡して処理をメインスレッドと分けることによってめっちゃ重たい処理をメインスレッドから切り離します。

import Foundation

class Operaion: NSOperation {

    override init() {
        super.init()
        self.queuePriority = NSOperationQueuePriority.Normal
    }

    override func main() {
        for i in 1...100 {
            NSLog("%@, Loop: %d", NSThread.currentThread(), i)
        }
    }

}

今回はOperationというクラスを実装しました。それを違うスレッドで処理するにはGCDで別スレッドを取得します。簡単ですね。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
    Operaion().start()
})

これだけで別スレッドでの処理が実現できます。

ただし、UIに関する処理は 必ず UIスレッド(メインスレッド)で行ってください。

※必ずしも、NSOperationクラスを別で実装する必要はありません。UIViewController上で定義しても良いですし、クロージャーで定義してもよいです。

NSOperationQueueクラス

大体の非同期な処理は先ほどの実装で済むかと思います。

ですが、タスクを何回かの複数のスレッド上で行いたい場合、しっかりとスレッドを管理してあげないと意図しない挙動となったり、ANRが発生することもあります。

では、そのスレッドを管理するマネージャークラスを自前しますか……Noですね。今の時代はなんでも揃っています。

FoundationフレームワークにはNSOperationQueueというものが存在します。

これを使って簡単に効率的でスレッドセーフなマルチスレッド処理を実装することができます。

var queue = NSOperationQueue()

使い方

必要なところでNSOperationQueueaddOperationメソッドにNSOperationで定義されたサブクラスを突っ込みます。

var queue = NSOperationQueue()

for i in 1...10 {
    queue.addOperation(Operaion())
}

これで、maxConcurrentOperationCountに設定されているスレッド数で処理が並行に走ります。

おわりに

この記事は昨日書いたAndroidのマルチスレッドの話をiOSに変えてみました。

そのため、Android <--> iOSで相互にスレッドの話を理解したい人、どうぞ一例として参考にしてみてください。


今回、改めてiOSとAndroidのスレッドを比較しましたが、NSOperationQueueはかなり使いやすいですね。

今回のサンプルプロジェクトのリポジトリはこちらです。

今回はスレッドに関してで、UIスレッドには触れていません。

ですが、UIスレッドとの連携も考える必要はあります。また、今度時間があればいろいろと紹介します。

昨日のAndroid Advent Calendar 2014の記事もよろしくお願いします。

※無理やり、Androidの話を変えた部分もあるので、省略等多いですが多めに見てあげてください

46
44
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
46
44