How to work with NSOperationQueue and NSBlockOperation with dispatch gcd?

两盒软妹~` 提交于 2019-12-12 03:17:40

问题


Here is the code

@interface ViewController ()
@property (nonatomic, strong) NSOperationQueue *queue;
@end


@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];

    _queue = [[NSOperationQueue alloc] init];

    NSBlockOperation *aBlockOperation = [[NSBlockOperation alloc] init];
    __weak NSBlockOperation* aWeakBlockOperation = aBlockOperation;

    [aBlockOperation addExecutionBlock:^{
        NSLog(@"queue should still have the operation. And it does. yay!: %@", [_queue operations]); // This should print correctly. It will show the NSBlock operation correctly residing inside the NSOperationQueue
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"Now queue is empty??: %@", [_queue operations]); // This should print as being empty
            NSLog(@"And a weak block is nil???: %@", aWeakBlockOperation); // This should print out **nil**
            if (![aWeakBlockOperation isCancelled]) {
                // Now i have no way to check the operation
            }

        });
    }];

    [_queue addOperation:aBlockOperation];
@end

[Edit] The goal is to have a user interaction like this: There is a tableView on screen with 5 or more cells. When ever a user click a cell, background process will perform background process that will take a while. The App will, at 3 second intervals, check to see if the user clicked on another cell. If the user clicked on another cell, I should cancel the current operation from queue, and begin processing the new one the user clicked on.

From the code above i have 2 problems i cant solve.

  1. How do i make it so that my weak reference isnt deallocated in the dispatch_after block? The goal of putting it there is to pause the app for exactly 3 seconds. If dispatch_after is incorrect, then what code do i use there to prevent it becoming nil?

  2. Why is it that my NSOperationQueue become empty after I call dispatch_after? Is there a way to make it not become empty?


回答1:


dispatch_after schedules the block and returns immediately. So, your NSBlockOperation's executionBlock has almost no work to do — it immediately finishes and is removed from the queue. At that time, the operation is released and so the weak reference becomes nil before the dispatch_after block is called later.

If you do the dispatch_after first and schedule the operation from inside that block, it might suit your needs. You could just use sleep, but I wouldn't recommend that since you will be unnecessarily blocking a thread. See this question for more discussion on NSOperation and delays.




回答2:


You can schedule operation inside the dispatch_after block and declare aBlockOperation as an instance variable/property so aWeakBlockOperation will not became nil.

But you do not need to hassle with the NSBlockOperation to achieve your goal. You can use dispatch_block_t instance variable which you would set to a new value (block with your code you need to be executed after the column is clicked) each time the column is clicked:

@implementation ViewController
{
    dispatch_block_t columnBlock;
}

- (void)columnClicked
{
    columnBlock = ^{ ... your code ... };
    __weak dispatch_block_t weakColumnBlock = columnBlock;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            dispatch_block_t colBlock = weakColumnBlock;
            if (colBlock)
                colBlock();
    });
}


来源:https://stackoverflow.com/questions/32920793/how-to-work-with-nsoperationqueue-and-nsblockoperation-with-dispatch-gcd

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!