名前 | 説明 |
---|---|
直列ディスパッチキュー serial dispatch queue |
現在実行中の処理の終了を待ってから、次の処理を実行する |
並列ディスパッチキュー concurrent dispatch queue |
現在実行中の処理の終了を待たずに次の処理を並列で実行する |
ディスパッチキューを利用するには、既存のディスパッチキューを取得するか、新規のディスパッチキューを取得する。
名前 | 直列・並列 | 説明 | 取得方法 |
---|---|---|---|
メインキュー main queue |
直列 | メインスレッドで処理を実行する | let queue = DispatchQueue.main |
グローバルキュー global queue |
並列 | 現在実行中の処理の終了を待たずに次の処理を並列で実行する | let queue = DispatchQueue.global(qos: .userInitiated) |
グローバルキューは実行優先度 (qualiity of service、QoS)によって次の5種類がある:
userInteractice
ユーザーからの入力に対してインタラクティブに実行され、即時に実行されなければフリーズしているように見える処理に用いるuserInitiated
ユーザーからの入力を受けて実行される処理に用いるdefault
utility
視覚的な情報の更新を伴いつつも即時の結果を要求しない処理に用いるbackground
バックアップなど、目に見えないところで行われ、数分〜数時間かかっても問題ない処理に用いる
public struct DispatchQoS : Equatable {
public let qosClass: DispatchQoS.QoSClass
public let relativePriority: Int
public static let background: DispatchQoS
public static let utility: DispatchQoS
public static let `default`: DispatchQoS
public static let userInitiated: DispatchQoS
public static let userInteractive: DispatchQoS
public static let unspecified: DispatchQoS
public enum QoSClass {
case background
case utility
case `default`
case userInitiated
case userInteractive
case unspecified
public init?(rawValue: qos_class_t)
public var rawValue: qos_class_t { get }
}
public init(qosClass: DispatchQoS.QoSClass, relativePriority: Int)
}
let newQueue = DispatchQueue(
label: "com.my_company.my_app.upload_queue",
qos:.default,
attributes:[.concurrent]//[]なら直列ディスパッチキューを作成,.concurrentを追加すると並列ディスパッチキューを取得
)
DispatchQueue
型のasync(execute:)
メソッドを利用する。
タスクの追加方法は直列・並列で共通。
queue.async {
print("非同期の処理")
}
ここはMixiのトレーニングコースの引き写しなので、ObjCになりますがご了承くださいm(-_-)m。
なお、タスク同士の依存関係の定義や、条件に応じたタスクのキャンセルを実装する場合は、Operation
クラスとOperationQueue
クラスを検討のこと。
グループに追加したすべてのタスクが終わってから以下の処理を実行したい場合に使う。
例:
dispatch_group_t group = dispatch_group_create(); // 1. dispatch group の生成
for (NSInteger i = 0 ; i < 100; ++i) {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 2. タスクをdispatch_queue に追加
dispatch_group_async(group, queue, ^{
NSLog(@"%d", i);
});
}
// 3. タスクの終了まで待機
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"here!!");
// 4. 不要になったgroupをrelease
dispatch_release(group);
排他的に非同期処理を行う。
例:
dispatch_queue_t queue = dispatch_queue_create("jp.mixi.ios.sample.barrier", DISPATCH_QUEUE_CONCURRENT);
NSMutableString *string = [NSMutableString string];
for (NSInteger i = 0 ; i < 100; ++i) {
if (i % 10 == 0) { // 書き込み処理
// barrier async
dispatch_barrier_async(queue, ^{
[string deleteCharactersInRange:NSMakeRange(0, string.length)];
[string appendFormat:@"%02d", i];
});
} else { // 読み込み処理
dispatch_async(queue, ^{
NSLog(@"%02d : string = %@", i, string);
});
}
}
ここからSwiftに戻ります^^;
単純な非同期処理の場合、GCDを直接利用すべきだが、タスクのキャンセル、タスク間の依存関係を指定するにはOperationクラスを利用すべき。
mixiのBlocksの解説が詳しいのでそちらをご覧ください。他に参考になったのは [Objective-C] Blocksがややこいのでまとめてみる ですね!