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

多线程-NSOperation和NSOperationQueue

作者头像
進无尽
发布2018-09-12 18:23:26
1.1K0
发布2018-09-12 18:23:26
举报
文章被收录于专栏:進无尽的文章進无尽的文章
NSOperation

NSOperation类是用来封装在单个任务相关的代码和数据的抽象类。NSOperation 是苹果公司对 GCD 的封装,完全面向对象,所以使用起来更好理解。 ** 因为它是用来封装任务的,大家可以看到 NSOperation 和 NSOperationQueue 分别对应 GCD 的 任务 和 队列, 但是NSOperation本身又有执行多线程的能力跟GCD里的任务还是有区别的** 。

操作步骤也很好理解:

  • 将要执行的任务封装到一个 NSOperation 对象中。
  • 将此任务添加到一个 NSOperationQueue 对象中。 然后系统就会自动在执行任务。
创建任务

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

代码语言:javascript
复制
 #.创建NSInvocationOperation对象
  NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
  //开始执行
 [operation start];
 # 创建一个NSOperation不应该直接调用start方法(如果直接start则会在主线程中调用)而是应该放到NSOperationQueue中启动。

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

注意:之前说过这样的任务,默认会在当前线程执行。但是 NSBlockOperation 还有一个方法:addExecutionBlock: ,通过这个方法可以给 Operation 添加多个执行 Block。这样 Operation 中的任务 会并发执行,它会 在主线程和其它的多个线程 执行这些任务.。并且ddExecutionBlock 方法必须在 start() 方法之前执行,否则就会报错。

代码语言:javascript
复制
# 创建NSBlockOperation对象
  NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
      NSLog(@"%@", [NSThread currentThread]);
  }];
# 添加多个Block
  for (NSInteger i = 0; i < 5; i++) {
      [operation addExecutionBlock:^{
          NSLog(@"第%ld次:%@", i, [NSThread currentThread]);
      }];
  }
  #开始任务,你会发现,会在多个线程中打印,其中包括主线程。
 [operation start];

自定义Operation

除了上面的两种 Operation 以外,我们还可以自定义 Operation。自定义 Operation 需要继承 NSOperation 类,并实现其 main() 方法,因为在调用 start() 方法的时候,内部会调用 main() 方法完成相关逻辑。所以如果以上的两个类无法满足你的欲望的时候,你就需要自定义了。你想要实现什么功能都可以写在里面。除此之外,你还需要实现 cancel() 在内的各种方法。

创建队列

我们可以调用一个 NSOperation 对象的 start() 方法来启动这个任务,这个默认是 同步执行 的。就算是 addExecutionBlock 方法,也会在 当前线程和其他线程 中执行,也就是说还是会占用当前线程。如果你不想这个任务在主线程中执行(代码默认情况下都在主线程中执行。)这是就要用到队列 NSOperationQueue 。按类型来说的话一共有两种类型:主队列、其他队列。只要添加到队列,会自动调用任务的 start() 方法。

  • 主队列 主队列是串行队列,添加到主队列的任务都会一个接一个地排着队在主线程处理。 # 获取到主队列 NSOperationQueue *queue = [NSOperationQueue mainQueue];
  • 其他创建的队列 主队列比较特殊,所以会单独有一个类方法来获得主队列。并且其他队列的任务会在其他线程并行执行。请注意这里是并行执行。 #1.创建一个其他队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; #2.创建NSBlockOperation对象 NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"%@", [NSThread currentThread]); }]; #.添加多个Block for (NSInteger i = 0; i < 5; i++) { [operation addExecutionBlock:^{ NSLog(@"第%ld次:%@", i, [NSThread currentThread]); }]; } #.队列添加任务 [queue addOperation:operation];
NSOperationQueue的一些特殊使用
  • 设置最大并发数

我们将 NSOperationQueue 与 GCD的队列 相比较就会发现,这里没有串行队列,那如果我想要10个任务在其他线程串行的执行的话,NSOperationQueue 有一个参数 maxConcurrentOperationCount 最大并发数,用来设置最多可以让多少个任务同时执行。当你把它设置为 1 的时候,就相当于是串行队列了

  • NSOperationQueue 添加一个任务到队列 - (void)addOperationWithBlock:(void (^)(void))block; 这样就可以添加一个任务到队列中了。
  • NSOperation 之间添加依赖 NSOperation 有一个非常实用的功能,那就是对任务添加依赖。比如有 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.不能添加相互依赖,会死锁,比如 A依赖B,B依赖A。 B.可以使用 removeDependency 来解除依赖关系。 C.可以在不同的队列之间依赖,依赖是添加到任务身上的,和队列没关系。
  • 线程的挂起 #pragma mark - 线程的挂起 #暂停继续(对队列的暂停和继续),挂起的是队列,不会影响已经在执行的操作 - (IBAction)pause:(UIButton *)sender { //判断操作的数量,当前队列里面是不是有操作? if (self.opQueue.operationCount == 0) { NSLog(@"当前队列没有操作"); return; } self.opQueue.suspended = !self.opQueue.isSuspended; if (self.opQueue.suspended) { NSLog(@"暂停"); }else{ NSLog(@"继续"); } }
  • 取消队列里的所有操作 #pragma mark - 取消队列里的所有操作 - (IBAction)cancelAll:(UIButton *)sender { # 只能取消所有队列的里面的操作,正在执行的无法取消 # 取消操作并不会影响队列的挂起状态 [self.opQueue cancelAllOperations]; NSLog(@"取消队列里所有的操作"); //取消队列的挂起状态 #(只要是取消了队列的操作,我们就把队列处于不挂起状态,以便于后续的开始) self.opQueue.suspended = NO; }
其他方法

以上就是一些主要方法, 下面还有一些常用方法需要大家注意:

代码语言:javascript
复制
#  NSOperation
BOOL executing; //判断任务是否正在执行
BOOL finished; //判断任务是否完成
#当一个 operation 被取消时,它的 completion block 仍然会执行,
#所以我们需要在真正执行代码前检查一下 isCancelled 方法的返回值。
- void (^completionBlock)(void); //用来设置完成后需要执行的操作
 
- (void)cancel; //取消任务
- (void)waitUntilFinished; //阻塞当前线程直到此任务执行完毕

#  NSOperationQueue
NSUInteger operationCount; //获取队列的任务数
- (void)cancelAllOperations; //取消队列中所有的任务
#阻塞当前线程直到此队列中的所有任务执行完毕
# **可以用来处理所有任务完成后的事件**
- (void)waitUntilAllOperationsAreFinished; 
[queue setSuspended:YES]; // 暂停queue
[queue setSuspended:NO]; // 继续queue
NSOperation和GCD的区别和类似的地方
  • GCD是纯C语言的API,NSOperationQueue是基于GCD的OC版本封装
  • GCD只支持FIFO的队列,NSOperationQueue可以很方便地调整执行顺序、设置最大并发数量
  • NSOperationQueue可以在轻松在Operation间设置依赖关系,而GCD需要写很多的代码才能实现
  • NSOperationQueue支持KVO,可以监测operation是否正在执行(isExecuted)、是否结束(isFinished),是否取消(isCanceld)
  • GCD的执行速度比NSOperationQueue快 **任务之间没有什么依赖关系,而是需要更高的并发能力:GCD ** 任务之间有依赖、或者要监听任务的执行情况、需要暂停、继续任务:NSOperationQueue

小结

以上就是关于 NSOperation和NSOperationQueue 的主要知识了,后期如果有更多内容会同步更新。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.02.14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • NSOperation
    • 创建任务
      • 创建队列
        • NSOperationQueue的一些特殊使用
        • 其他方法
          • NSOperation和GCD的区别和类似的地方
            • 小结
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档