こんにちは、JAGA(ja_gaimopotato)です。
NSOperationQueue
のaddOperationWithBlock
をキャンセルする方法を考えました。
果たして、どれがベストなのか。## cancelAllOperationsを呼ぶと
色々と非同期なコードを書くときにお世話になっている、NSOperationQueue
とaddOperationWithBlock
メソッド。
NSOperationQueue
には、cancelAllOperations
というメソッドがあります。
その名前のごとくNSOperation
を全てキャンセルするものだと思っていました。
ですが、これはNSOperation
クラスのcancel
メソッドを呼び出すだけのようですので、希望するキャンセル時の動作を実装したサブクラスが必要です。
キャンセルの手段を考える
特にaddOperationWithBlock
やNSBlockOperation
ではキャンセル時の動作が指定されていないようですので、どうするか考えました。
サブクラスを書かないで、キャンセルするとなるとループ内で判定するとか。
NSOperationQueue *queue = [NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
// しばらく終わらない処理
while () {
// メンバ変数でキャンセルかどうかを判断
if (_cancelFlagOn == YES ) return;
}
}];
__weakを利用した弱参照のweakBlockOperationをBlock内で評価するとか。
調べてみるとループ内ということなら他の方法もあるようでした。
NSBlockOperation
を先に変数blockOperationとして捕捉しておいて、普通にaddOperation
で加えるという方法をとって、__weakを利用した弱参照のweakBlockOperationをBlock内で評価しています。
ループ内で、weakBlockOperationがキャンセルされている場合は、そのBlockを終了するという処理をします。
NSBlockOperation *blockOperation = [[NSBlockOperation alloc] init];
__weak NSBlockOperation *weakBlockOperation = blockOperation;
[operation addExecutionBlock: ^ {
// しばらく終わらない処理
while () {
// ループ内でキャンセルを捕捉する。
if ([weakBlockOperation isCancelled]) return;
}
}];
[_queue addOperation:blockOperation];
というようなコードになります。
cocoa – [NSOperation cancelAllOperations]; does not stop the operation – Stack Overflow
ループ以外に閃かなかった。
どちらにしろ、ループ内でしかキャンセルする方法がないので、他の方法がないか模索中です。
現在の結論としては、サブクラス書くしかないかな。
ということになりました。