92
93

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

iOSAdvent Calendar 2012

Day 8

NSBlockOperationで手軽にキャンセル処理

Last updated at Posted at 2012-08-07

GCD便利ですね。手軽にネストした非同期処理を書けるので、使いまくっています。しかし一直線にコードを書いていると見過ごしがちなのが、キャンセル処理です。時間のかかる処理を途中で止める場合や、別のUIViewControllerに遷移するから処理そのものが必要なくなった場合に、処理を止めたい場合があります。具体的には以下の様なケースがあると思います。

  • 大きなファイルのアップロード中にキャンセルボタンを出したい
  • 画面遷移をしたら、前の画面で進行中の画像ダウンロードはキャンセルしたい

このような場合にGCDライクに使えて、しかもキャンセル処理ができのが組み込みクラスのNSBlockOperationです。早速使い方を見て行きましょう。weakのおかげでややこしいメモリ管理を考えなくて楽です。

-(void)heavyTask {
    if (!_queue)
        _queue = [[NSOperationQueue alloc] init];
    
    NSBlockOperation *operation = [[NSBlockOperation alloc] init];
    __weak NSBlockOperation *weakOperation = operation; // 循環参照を避ける
    [operation addExecutionBlock:^{
        for (int i = 0; i < 10; i++) {
            if (weakOperation.isCancelled) return;  // これを至る所に挟む
            [NSThread sleepForTimeInterval:1]; // 何か重い処理
        }
        NSLog(@"complete");
    }];
    
    [_queue addOperation:operation];
}

-(void)cancel {
    [_queue cancelAllOperations];
}

ではネストした処理のキャンセルを考えましょう。全く同じように直感的に書けます。NSOprationQueueがキャンセルの面倒を見てくれるので楽ですね。


-(void)heavyTask {
    if (!_queue)
        _queue = [[NSOperationQueue alloc] init];
    
    __weak NSOperationQueue *weakQueue = _queue;
    
    NSBlockOperation *firstOperation = [[NSBlockOperation alloc] init];
    __weak NSBlockOperation *weakFirstOperation = firstOperation; // 循環参照を避ける
    
    [firstOperation addExecutionBlock:^{
        for (int i = 0; i < 10; i++) {
            if (weakFirstOperation.isCancelled) return;  // これを至る所に挟む
            [NSThread sleepForTimeInterval:1]; // 何か重い処理
        }
        NSLog(@"next");
        NSBlockOperation *secondOperation = [[NSBlockOperation alloc] init];
        __weak NSBlockOperation *weakSecondOperation = secondOperation; // 循環参照を避ける
        [secondOperation addExecutionBlock:^{
            for (int i = 0; i < 10; i++) {
                if (weakSecondOperation.isCancelled) return;
                [NSThread sleepForTimeInterval:1]; // 何か重い処理
            }
            NSLog(@"complete");
        }];
        [weakQueue addOperation:secondOperation];
    }];
            
    [_queue addOperation:firstOperation];
}

-(void)cancel {
    [_queue cancelAllOperations];
}

ここまでやるとだいぶコードが見づらいですね…。しかしDelegate等で書くと、(設計的には綺麗ですが)後から追いづらくなるので、こっちの方がましではないかと思ってます。

以上NSBlockOperationでキャンセル処理を行う方法の紹介でした。NSOperationQueueは裏側でGCDを使っているので、GCD+キャンセル機能が欲しいという用途には最適だと思います。

92
93
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
92
93

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?