web-dev-qa-db-ja.com

iOS Swiftでマルチスレッド、同時実行、または並列処理を行う方法

Swiftでワーカースレッドを作成する方法はありますか?たとえば、多くの計算を必要とする主要な機能があり、メインスレッドが数秒間遅延する場合、その機能を別のスレッドまたはメインスレッドをブロックしないスレッドは、Swiftでそれを行う方法はありますか?

AppleのSwiftドキュメントの基本および高度なコンポーネントを調べましたが、並行性や並列性については何もありません。

36
Martin Cazares

または、操作キューも使用できます。 In Swift 3:

let queue = OperationQueue()

queue.addOperation() {
    // do something in the background

    OperationQueue.main.addOperation() {
        // when done, update your UI and/or model on the main queue
    }
}

これ、またはGCD( Andyの図解 )は正常に機能します。

操作キューとディスパッチキューの相対的なメリットについては、Appleの 同時実行プログラミングガイド を参照してください(Grand Central Dispatch、GCD)。このガイドでは、Objective-Cを使用した例を示していますが、APIと概念はSwift(基本的にSwift構文を使用)で同じです。 XcodeのGCDと操作キューのドキュメントでは、Objective-CとSwift APIの両方について説明しています。


ところで、上記の例とAndyのGCDデモの両方で、「トレーリングクロージャ」を使用していることに気付くでしょう。たとえば、定義addOperationWithBlockを見ると、それは「クロージャ」(Objective-Cのブロックに類似)である1つのパラメータを持つ関数として定義されています。

func addOperation(_ block: @escaping () -> Swift.Void)

そのため、次のように呼び出すと仮定することになります。

queue.addOperation({
    // do something in the background
})

ただし、関数の最後のパラメーターがクロージャーの場合、最後のクロージャー構文を使用すると、関数の括弧からその最終クロージャーパラメーターを取り出して、関数の後に移動できます。

queue.addOperation() {
    // do something in the background
}

そして、括弧内には何も残っていないので、さらに一歩進んで空の括弧を削除することもできます。

queue.addOperation {
    // do something in the background
}

NSOperationQueue/OperationQueueやGCDの関数宣言を解釈し、コードで使用する方法を示していることを願っています。

46
Rob

そのようなタスクには、Grand Central Dispatch(GCD)を使用できます。

これは基本的な例です:

let backgroundQueue: dispatch_queue_t = dispatch_queue_create("com.a.identifier", DISPATCH_QUEUE_CONCURRENT)

// can be called as often as needed
dispatch_async(backgroundQueue) {
    // do calculations
}

// release queue when you are done with all the work
dispatch_release(backgroundQueue)
17
Andy

このライブラリ を使用すると、並行処理を非常に表現力豊かに記述することができます。

func handleError(_ error) { ... }

HoneyBee.start(on: DispatchQueue.main) { root in
    root.setErrorHandler(handleError)
        .chain(function1) // runs on main queue
        .setBlockPerformer(DispatchQueue.global())
        .chain(function2) // runs on background queue
        .branch { stem in
            stem.chain(func3) // runs in parallel with func4
            +
            stem.chain(func4) // runs in parallel with func3
        }
        .chain(func5) // runs after func3 and func4 have finished
        .setBlockPerformer(DispatchQueue.main)
        .chain(updateUIFunc)
}
0
Alex Lynch