前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS多线程GCD任务取消->NSOperation

iOS多线程GCD任务取消->NSOperation

作者头像
清墨
发布2019-04-17 17:00:14
2.8K0
发布2019-04-17 17:00:14
举报
文章被收录于专栏:清墨_iOS分享清墨_iOS分享

在多线程开发中,我们常用到GCD,这里探讨一下GCD任务的取消: 1.在iOS 8以后,系统给我们提供了这样的取消函数 dispatch_block_cancel,不过这个也只能用于dispatch_block_create创建的dispatch_block_t,我们试验一下:

代码语言:javascript
复制
-(void)GCD_cancel{
    dispatch_queue_t queue = dispatch_queue_create("concurrent", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_block_t block1 = dispatch_block_create(0, ^{
        NSLog(@"1");
    });
    
    dispatch_block_t block2 = dispatch_block_create(0, ^{
        NSLog(@"2");
    });
    
    dispatch_block_t block3 = dispatch_block_create(0, ^{
        NSLog(@"3");
    });
    
    dispatch_async(queue, block1);
    dispatch_async(queue, block2);
    dispatch_async(queue, block3);
    
//    dispatch_block_cancel(block1);
    
}

这时肯定是任务都会执行的

代码语言:javascript
复制
2019-04-03 14:11:14.896059+0800 Timer[8755:2877034] 1
2019-04-03 14:11:14.896063+0800 Timer[8755:2877035] 2
2019-04-03 14:11:14.896064+0800 Timer[8755:2877036] 3

接下来,把注释的那一行 dispatch_block_cancel(block1);打开,看看效果:

代码语言:javascript
复制
2019-04-03 14:12:27.749116+0800 Timer[8776:2877773] 2
2019-04-03 14:12:27.749116+0800 Timer[8776:2877770] 3

我们发现block1确实被取消掉了。这是dispatch_block_cancel的用法。

2.很多时候,我们的场景不会去用dispatch_block_create创建dispatch_block_t,这个时候我们若想取消一个任务,可以考虑用一个条件来做,满足条件则执行此任务,不满足则不执行,举个例子:

代码语言:javascript
复制
static BOOL sholdCancel = NO;

-(void)GCD_cancel{
    dispatch_queue_t queue = dispatch_queue_create("concurrent", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        NSLog(@"任务已经开始了");
        for (int i=0; i<100; i++) {
            if (sholdCancel) {
                NSLog(@"在i=%d的时候已经取消了",i);
                break;
            }
            NSLog(@"%d",i);
            sleep(1);
        }
        
    });
    
    [self performSelector:@selector(GCD_shouldCancel) withObject:nil afterDelay:5.0];
    
}

-(void)GCD_shouldCancel{
    sholdCancel = YES;
}

效果如下:

代码语言:javascript
复制
2019-04-03 15:07:49.379672+0800 Timer[9444:2906947] 任务已经开始了
2019-04-03 15:07:49.379872+0800 Timer[9444:2906947] 0
2019-04-03 15:07:50.383439+0800 Timer[9444:2906947] 1
2019-04-03 15:07:51.386239+0800 Timer[9444:2906947] 2
2019-04-03 15:07:52.388414+0800 Timer[9444:2906947] 3
2019-04-03 15:07:53.389778+0800 Timer[9444:2906947] 4
2019-04-03 15:07:54.394204+0800 Timer[9444:2906947] 在i=5的时候已经取消了

写到这里,这儿其实还隐藏了一个知识点,就是block的变量捕获,有兴趣或是不理解的朋友可以研究一下。(如下,为何输出不是20而是10)

代码语言:javascript
复制
int a = 10;
void (^blcok)() = [^{
    NSLog(@"%d",a);
} copy];

a=20;

blcok(); // log : a = 10

3.过渡到NSOperation NSOperation是对GCD的封装,底层也是GCD。 NSOperation给我们封装了更多的api,这是我在Xcode中提出来的:

代码语言:javascript
复制
@interface NSOperation : NSObject {
@private
    id _private;
    int32_t _private1;
#if __LP64__
    int32_t _private1b;
#endif
}

- (void)start;
- (void)main;

@property (readonly, getter=isCancelled) BOOL cancelled;
- (void)cancel;

@property (readonly, getter=isExecuting) BOOL executing;
@property (readonly, getter=isFinished) BOOL finished;
@property (readonly, getter=isConcurrent) BOOL concurrent; // To be deprecated; use and override 'asynchronous' below
@property (readonly, getter=isAsynchronous) BOOL asynchronous API_AVAILABLE(macos(10.8), ios(7.0), watchos(2.0), tvos(9.0));
@property (readonly, getter=isReady) BOOL ready;

- (void)addDependency:(NSOperation *)op;
- (void)removeDependency:(NSOperation *)op;

@property (readonly, copy) NSArray<NSOperation *> *dependencies;

typedef NS_ENUM(NSInteger, NSOperationQueuePriority) {
    NSOperationQueuePriorityVeryLow = -8L,
    NSOperationQueuePriorityLow = -4L,
    NSOperationQueuePriorityNormal = 0,
    NSOperationQueuePriorityHigh = 4,
    NSOperationQueuePriorityVeryHigh = 8
};

@property NSOperationQueuePriority queuePriority;

@property (nullable, copy) void (^completionBlock)(void) API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));

- (void)waitUntilFinished API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));

@property double threadPriority API_DEPRECATED("Not supported", macos(10.6,10.10), ios(4.0,8.0), watchos(2.0,2.0), tvos(9.0,9.0));

@property NSQualityOfService qualityOfService API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0));

@property (nullable, copy) NSString *name API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0));

@end

我们可以发现它有状态属性,有取消方法,也有添加依赖方法等...这里我们还是先说取消吧,下面来给大家写个demo:

代码语言:javascript
复制
-(void)operationCancel{
    NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"1");
    }];
    
    NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"2");
    }];
    
    NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"3");
    }];
    
    [operation1 start];
    [operation2 start];
    [operation3 start];
    
    [operation1 cancel];
}

这时输出是:

代码语言:javascript
复制
2019-04-03 14:51:44.512940+0800 Timer[9248:2898426] 1
2019-04-03 14:51:44.513114+0800 Timer[9248:2898426] 2
2019-04-03 14:51:44.513213+0800 Timer[9248:2898426] 3

因为正在执行的任务,NSOperation也是不能取消的,所以也是需要将cancel在start前调用的(就如同满足一个条件是否需要cancel一样,也可以满足条件不调用start)

代码语言:javascript
复制
-(void)operationCancel{
    NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"1");
    }];
    
    NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"2");
    }];
    
    NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"3");
    }];
    
    [operation1 cancel];  //这里调用
    
    [operation1 start];
    [operation2 start];
    [operation3 start];
    
//    [operation1 cancel];
    
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.04.03 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档