NSOperation和NSOperationQueue

概述

NSOperation 是苹果公司对 GCD 的封装,完全面向对象,所以使用起来更好理解。 大家可以看到 NSOperation 和 NSOperationQueue 分别对应 GCD 的 任务队列
操作步骤主要就两步:

  • 将要执行的任务封装到NSOperation中;
  • 将此任务添加到NSOperationQueue中。

添加任务

NSOperation 只是一个抽象类,所以不能封装任务。但它有 2 个子类用于封装任务。分别是:NSInvocationOperationNSBlockOperation 。创建一个 Operation 后,需要调用 start 方法来启动任务,它会 默认在当前队列同步执行。当然你也可以在中途取消一个任务,只需要调用其 cancel 方法即可。

  • NSInvocationOperation :初始化
    //1.创建NSInvocationOperation对象
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
    
    //2.开始执行
    [operation start];
    
- NSBlockOperation: 初始化

//1.创建NSBlockOperation对象
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
}];
//2.开始任务
[operation start];

> 这样添加的任务,会默认在当前线程执行。不过```NSBlockOperation```提供了这个方法```addExecutionBlock:```,可以给operation添加多个block,这样operation中的任务就会**并发执行**,。他会在**主线程和其他多个线程**执行这些任务

注:```addExecutionBlock``` 方法必须在 start() 方法之前执行,否则就会报错:

‘*** -[NSBlockOperation addExecutionBlock:]: blocks cannot be added after the operation has started executing or finished'


### 添加队列
我们通过``` NSOperation``` 对象的``` start() ```方法来启动这个任务,事实上系统默认是 **同步执行** 的。就算是 ```addExecutionBlock``` 方法,也会在 **当前线程和其他线程 中执行**,也就是说还是会占用当前线程。这时就要用到队列 **NSOperationQueue** 了。一般分为两种队列:主队列、其他队列。**只要添加到队列,会自动调用任务的 start() 方法**。
-  主队列
通过调用```mainQueue```类方法创建的是为主队列。

NSOperationQueue *queue = [NSOperationQueue mainQueue];

- 其他队列
 因为主队列比较特殊。个人觉得是主队列是单例,所以统一用一个类方法来返回。通过初始化产生的队列,就是其他队列。其他队列的任务会在其他线程并行执行

//1.创建一个其他队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];

//2.创建NSBlockOperation对象
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
}];

//3.添加多个Block
for (NSInteger i = 0; i < 5; i++) {
[operation addExecutionBlock:^{
NSLog(@"第%ld次:%@", i, [NSThread currentThread]);
}];
}

//4.队列添加任务
[queue addOperation:operation];

#####需要注意
 运行上面代码,会发现这里并没有串行队列,和GCD并不同。如果想要实现,则可以设置```NSOperationQueue```中```maxConcurrentOperationCount```这个属性。该属性是设置最大并发数,用来设置最多可以让多少个任务同时执行。因此设置为```1```即可。

```NSOperationQueue``` 还有一个快速添加任务的方法,```- (void)addOperationWithBlock:(void (^)(void))block;```这样就可以添加一个任务到队列中了,十分方便。

#### 依赖
 **场景**
 比如有 3 个任务:A: 从服务器上下载一张图片,B:给这张图片加个水印,C:把图片返回给服务器。这时就可以用到依赖了

//1.任务一:下载图片
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"下载图片 - %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:1.0];
}];

//2.任务二:打水印
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"打水印 - %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:1.0];
}];

//3.任务三:上传图片
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"上传图片 - %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:1.0];
}];

//4.设置依赖
[operation2 addDependency:operation1]; //任务二依赖任务一
[operation3 addDependency:operation2]; //任务三依赖任务二

//5.创建队列并加入任务
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperations:@[operation3, operation2, operation1] waitUntilFinished:NO];

使用注意:
 - 不能相互依赖, A依赖B,B依赖A,这样会造成死锁
 - 可以使用方法```removeDependency ```解除依赖
 - 依赖是添加到任务上的。因此,依赖是跨队列的。

>  未完待续
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容