【swift】非同期処理後のクロージャの処理が遅いとき

ObjectiveCで用意されていた関数や,ObjectiveC関連の情報をあさっていると,頻繁にクロージャに出くわす.

[hogeSuccess:^{
    hogehoge;
}];

よく,クロージャとかブロック構文とか呼ばれるヤツだ.
^自体はブロックと呼ばれるもので,これを関数の引数に渡しているから,ブロック変数とか呼ばれていたりする.
使用方法は関数の引数に限らず,他のところでも使えるのだが,とりあえずこれをブロック変数として使っているメソッドが,結構いっぱい用意されている.
swiftクロージャが定義されているメソッドを呼ばなきゃいけないときや,自分でクロージャを使いたいことがよくあるのでメモしておく.



引数を取らないクロージャをsiwftで

// 定義
func hogeSuccess(success:()->Void) {
    // なんか処理
    success()
}

// 呼び出し
hogeSuccess({() in
    // なんか処理してたのが終わったらhogehogeが実行される
    hogehoge
})

ここまでは割りとラクにできる.

引数を一つ取るクロージャ

// 定義
func hogeSuccess(success:(Int)->Void) {
    // indexが算出される
    success(index)
}


// 呼び出し
hogeSuccess({index in
    hogehoge
    println(index)
})

引数を複数取るクロージャ

// 定義
func hogeSuccess(success:(Int, String, Array)->Void) {
    success(index, string, array)
}

// 呼び出し
hogeSuccess({index, string, array in
    hogehoge
    println(index)
    println(string)
    println(array)
})

とまぁこんな感じで.


非同期処理後のクロージャの処理

本題です.
なんでクロージャなんてものをメソッドの引数に埋め込む必要があるかというと,非同期処理を走らせるからです.
呼び出したメソッドの処理が完全に終わってから実行して欲しい処理というのが,結構あるんです.
これを実現するためにクロージャに処理を渡しているんですね.

で,処理が完了した後に,渡された処理を実行するように定義してやると.


これをswiftで実現してみたのですが,なんかクロージャ内の処理がやたら遅い.

break pointを仕込んでみたのですが,どうやら処理自体は走っています.
ただ,その処理の中で,表示関連の処理を書いておくと(例えばアラートの表示とか),やたら後になってからアラートが表示されたりします.


※これはObjectiveCでも同様の対応が必要になる場合があるので,swiftに限定した話ではないです


なんでなの?

これ,非同期処理の部分がメインのスレッドで実行されてないからです.
さっさと実行したい場合には,こいつをメインのスレッドで強制的に実行してやります.

// 定義
func hogeSuccess(params: NSDictionary, success:(Int, String)->Void) {
    // なんか処理をする,ついでにindexとstrも算出
    success(index, str)
}

この関数を呼び出すときに,クロージャの処理をメインのスレッドで実行させます.

hogeSuccess(parameter, success:{ index, str in
    var q_main: dispatch_queue_t = dispatch_get_main_queue()
    dispatch_async(q_main, {() in
        // クロージャ内でやりたかったこと
    })
})

dispatch_get_main_queueを取ってきて,強制的にそいつに処理を投げています.
こうすることでクロージャ内の処理が,なんかやたら後になって実行されるのは回避できます.


参考:
http://qiita.com/nnasaki/items/6e237901bce5f3694295#2-4
http://qiita.com/kawachi/items/808b2c0e915b32116629
http://tech.basicinc.jp/Objective-C/2013/08/22/objective-c_image_load/