DispatchSemaphore
を使うと非同期処理を同期的に処理するために待機したりできる。
let semaphore = DispatchSemaphore(value: 0)
みたいな感じで初期化できるがこのvalue
がキモ。semaphoreは内部でカウンターを持つ。valueはカウンターの初期値となる。
-
semaphore.signal()
をするとカウンターが+1
される -
semaphore.wait()
をするとカウンターが-1
される
wait()
はカウンターが0以上になるまで処理を止めて待機状態になる(以降の行が実行されないで止まる)。初期値が0の場合、wait()
をn回叩いたら、signal()
がn回叩かれるまで処理が止まるという感じ。
タイムアウトのあるwaitもある。→wait(timeout: )
使い方
// 3秒でタイムアウトするwait
switch semaphore.wait(timeout: .now() + 3) {
case .success:
// 3秒以内にsignalをもらった
// うまくいったときの処理
case .timedOut:
// 3秒待ってもsignalが来なかった
// タイムアウトの時の処理
}
ここで内部カウンターについて注意点。
-
semaphore.wait(timeout:)
の行に到達した時点で-1
される -
.success
の場合、外部でsignalが叩かれているはずなので+1
される -
.timedOut
の場合、外部でsignalが叩かれていないけれど、+1
される
つまり、wait(timeout:)
の場合、成功しようが失敗しようがカウントは+1
される。
これを知らないとsemaphoreのカウンターをうまく処理できずに無限ループになったり、意図通りのループにならなかったりするかも。