- 2016/03/10 コードを修正
非同期で処理を行うときに、◯秒未満で処理が終わってしまうときは◯秒待つまで待たせてメインスレッドに処理を戻すようにして、
◯秒以上かかるときは通常通り処理が終わり次第メインスレッドに処理を戻すようにしたい場面があったので、関数化して使えるようにしました。
コード1
func wait_atleast(time : NSTimeInterval, @noescape _ block: () -> Void) {
let start = CFAbsoluteTimeGetCurrent()
block()
let end = CFAbsoluteTimeGetCurrent()
let wait = max(0.0, time - (end - start))
if wait > 0.0 {
NSThread.sleepForTimeInterval(wait)
}
}
処理にかかった時間と、最低でも◯秒待って欲しいと指定した時間の差を取って、残り待ち時間があればsleepをかけて、
がなければそのまま、といった感じです。
待ち時間を最低5秒と設定した場合、
- 処理が3秒しかかからなかった→2秒待つ
- 処理が6秒かかった→待ち時間を超えているのでsleepはかけない
となります。
循環参照について
引数で渡すClosureに対して@noescape
を指定しているため、この処理に関してはselfをキャプチャする必要はありません。
wait_atleast(1.0) { [weak self] in
self?.hoge = ""
}
※ただ、dispatch_async
とセットで用いる事になると思うので、dispatch_async
でのClosureに対しては weak/unowned でのキャプチャが必要です。
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { [weak self] in
self?.hoge = "hoge"
wait_atleast(1.0) { // ここで [weak self] in は不要
self?.hoge = "fuga" // @noescapeではあるが、`dispatch_async`の範囲内なので、`self?.`は必要
}
}
使用例
例えば非同期で何か処理を行うときに、すぐ終わる時もあれば、数秒かかる時もあるような場合で、
HUD(例だとSVProgressHUD)を表示して処理を行うが、すぐ終わるときにHUDがすぐに消えてしまって
ユーザーにHUDで表示した文字を認識してもらえない場合もあったりします。。
(表示がでてすぐ消えちゃうと、なんだなんだ?ってなるので)
そんなときにもしすぐ処理が終わっても、1秒は待たせるときは、以下のように記述します。
SVProgressHUD.showWithStatus("保存中です...")
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { [weak self] in
wait_atleast(1.0) {
self?.saveImage()
}
dispatch_async(dispatch_get_main_queue()) {
SVProgressHUD.showSuccessWithStatus("保存しました")
}
}
端末の処理速度、処理の時の条件によっては早かったり遅かったりする時間を最低◯秒は非同期処理しているように見せることができるので、
場合によってはアリなのかなって思います(ごまかしたりできるので)。
-
NSDate()から、CFAbsoluteTimeGetCurrent()に変更しました。 ↩