RubyMotionで非同期処理の終了を待機したかった
最近ALAssetLibrary周りを触っているのだけど、非同期処理がけっこう多くてまともにつきあってるとコールバック地獄に入り込んでしまうので非同期処理を待つ方法を探した。
一応の解としては以下のようになった。このやり方がベストなのかどうかは分からない。
# 非同期処理を待つメソッドの定義 module Dispatch def self.wait_async(duration = 0.1, &block) @async_done = false queue_group = Dispatch::Group.new queue = Dispatch::Queue.concurrent(:default) queue.async(queue_group) { block.call } queue_group.notify(queue) { @async_done = true } CFRunLoopRunInMode(KCFRunLoopDefaultMode, duration, false) while !@async_done # 'queue_group.wait' が何故か効かなかったので end end # 呼び出し Dispatch.wait_async do # 何らかの非同期処理を含んだコード end p "done!" # 非同期処理が終わるまでここには来ない
だいたいRubyMotionのspecからパクって来た。
Dispatchモジュールにくっつけたのはなんとなく。
ちなみに非同期処理の終了をsleepで待つのはうまくいかない。非同期処理もいっしょにsleepしてしまうから?
2013-07-15追記
CFRunLoopRunInModeは単にdurationの間待つので、その間にたまたま非同期処理が終わってるだけだった。
終わるまで待つのではない。待ってたらたまたま終わったんだ。
その前段でqueueをごにょごにょしてるのとか意味ないw
queue_group.waitを呼ぶことで多分blockを呼び出すところまでは待機してくれるが、blockの中に非同期処理があったらそれはどっかに飛んでいってしまい、その非同期処理を待つことはできない。
そうだよ。非同期処理のそういう性質故にコールバック地獄がこの世に顕現するのではないか。
これはテストを書くには使えるが実際のアプリのコードに入れるのは無理だ。