2014年1月22日水曜日

Block構文の罠

先日、ブロック構文で引っかかったので覚え書き。

たとえば、 イカのようなブロック構文を引数に保つメソッドを実装したとする。

- (void)blockTest:(id)arg
                       onSuccess:(void(^)(void))successBlock
                       onFailure:(void(^)(NSInteger errCode, NSError* error))failureBlock

この処理の中で通信とか遅い処理を行う。成功すればonSuccessが実行され、失敗すればonFailureが実行される、と言う作りである。

この時、

-(void)method
{
    [〜 blockTest:@"arg"
        onSuccess:^(void) {
            // 成功時処理
        }
        onFailure:^(NSInteger errCode, NSError *error) {
            // エラー処理
        }
    ];
    // 素通り
}
   
という処理はどう走るか。

実は、まず素通りし、methodからも抜けてしまう。
しかるのち、blockTestが実際に終了した時に、その結果に応じてonSuccessまたはonFailureのいずれか「だけ」が走る。
その時には素通りの部分は実行されない。

すなわち、(見かけ上)一旦抜けたメソッド内に、後から、非同期にまた戻ってくるということになる。
これは通常のCのプログラムでは考えられない動作なので理解が難しい。
(一旦抜けた関数の、さらにその中の一部の処理だけに戻ってくるというのはありえない。)

このブロック文はデリゲートの代わりだからこういうことになる。
なまじブロックでメソッド内に記述するからややこしくなるわけである。

ブロックは便利な記述方法ではあるが、プログラムの動きで言えば、記述の流れと処理の流れが一致せずわかりにくくなるので、
注意が必要である。

0 件のコメント:

コメントを投稿