dispatch_sync
は同一キュー内で呼び出すとデッドロックに陥ります。
今までメインスレッドを安全に同期的に呼び出す際は以下のように行っていました。
func safe_dispatch_sync_main(block: dispatch_block_t) {
if NSThread.isMainThread() {
block()
} else {
dispatch_sync(dispatch_get_main_queue(), block)
}
}
今回、dispatch_queue_create
で作成したキューを同期的に実行する方法がないか探した結果をメモします。
結論
dispatch_queue_get_label
を利用するとqueueのラベル名が取得できます。
ラベル名が異なればdispatch_sync
を呼び出し、同じであればブロックを直接実行します。
func safe_dispatch_sync(queue: dispatch_queue_t, block: dispatch_block_t) {
let queue_label = dispatch_queue_get_label(queue)
let current_label = dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL)
if queue_label != current_label {
dispatch_sync(queue, block)
} else {
block()
}
}
補足
同じキューかどうかかの判断をラベル名で行っているため、同じラベル名で複数作成されると別キューで実行される可能性があります。
※ただdispatch_sync
には原理的に入らないのでデッドロックになる最悪のパターンは回避できると思います。
※ラベル名をUUIDやランダムで作成するとより厳密に判別できると思います。