目录

  • 1.简介
  • 2.Operation对象
  • 3.自定义Operation对象
  • 4.通过Operation Queues运行Operation对象
  • 5.手动运行Operation对象

一、简介

  Cocoa提供一个NSOperation对象用于执行一些异步的任务,NSOperation只是承载任务的,只能通过把operation添加到operation queue运行或者手动开线程运行。NSOperation与GCD相似,都是Cocoa提供的多线程编程工具,但是NSOperation提交的任务如果还没有执行时可以取消的,而GCD的任务提交后就完全不受我们控制了。

二、Operation对象

  NSOperation 其实是一个虚类(它并非没有任何实现,相反它已经实现了一些常用的功能,只是cocoa限定了它不能直接实例化),只有继承实现后才能使用。cocoa实现了NSOperation的两个子类,分别是NSBlockOperation、NSInvocationOperation,这两个类可以用于执行一般的多线程任务。

  NSBlockOperation类的作用主要是管理block执行,可以是一个或者多个block。

  NSInvocationOperation类则是管理selector执行,这个只能是一个selector。

  我们只讲NSBlockOperation类,先看一个简单例子:

NSOperationQueue *queue = [[NSOperationQueue alloc]init];
NSBlockOperation * operationA = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"operation block A.");
}];
[queue addOperation:operationA];

// 输出// operation block A.

  可以看到创建一个NSBlockOperation任务并运行很简单。只要创建一个NSBlockOperation类出入一个任务block,再添加到一个NSOperationQueue(下文会讲到)对象就能运行了。

  学完这个例子我们再来学习NSBlockOperation的有哪些行为。

  NSBlockOperation是支持添加多个block任务,被添加的这些block任务是并行运行的。NSBlockOperation对象还可以设置一个complete block,在所有的block任务都执行完后就会执行这个complete block。看代码

  NSOperationQueue *queue = [[NSOperationQueue alloc]init];      NSBlockOperation * operationA = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"operation block A(1).");}];// 添加[operationA addExecutionBlock:^{NSLog(@"operation block A(2).");}];// 结束block[operationA setCompletionBlock:^{NSLog(@"operation block A compelete.");}];[queue addOperation:operationA];

  //输出  2017-01-10 16:26:30.306 IOSTest[74701:3177097] operation block A(1).  2017-01-10 16:26:30.306 IOSTest[74701:3177217] operation block A(2).  2017-01-10 16:26:30.308 IOSTest[74701:3177217] operation block A compelete.
 

  NSBlockOperation有个name属性,可以通过setName来设置,通过getName来获取。

  NSBlockOperation本身是有优先级的,当被添加到operation queue时,高优先级的operation优先执行。operation 对象可以通过setQueuePriority函数来设置优先级。

  我们还可以调用operation 对象的waitUntilFinished函数,挂起当前线程直到operation对象的任务都执行完成才返回。

  operation对象如果还没执行,你可以通过调用cancel函数取消operation的运行。

  operation对象与operation对象之间可以有依赖的关系。比如operation A依赖 operation B和 operation C,当准备执行A是会去获取B、C的状态,如果B C没有执行完成的话是不会执行的A的,只有到B C,执行完成后,才回去执行A。依赖使得你可以在使不同的operation对象可以串行运行。

  NSOperationQueue *queue = [[NSOperationQueue alloc]init];    NSBlockOperation * operationA = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"operation block A.");}];NSBlockOperation * operationB = [NSBlockOperation blockOperationWithBlock:^{[NSThread sleepForTimeInterval:1];NSLog(@"operation block B.");}];NSBlockOperation * operationC = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"operation block C.");}];// 依赖
    [operationA addDependency:operationB];[operationA addDependency:operationC];[queue addOperation:operationA];[queue addOperation:operationB];[queue addOperation:operationC];    //输出    2017-01-10 16:41:48.670 IOSTest[74726:3188994] operation block C.  2017-01-10 16:41:49.670 IOSTest[74726:3188761] operation block B.  2017-01-10 16:41:49.671 IOSTest[74726:3188761] operation block A

  operation对象的所有属性都支持KVO,可以用KVO来监听operation对象的属性变化及时掌握operation对象的状态变化,其中有这些属性:

  • ready  - 正在准备
  • cancelled   - 是否取消
  • executing  - 正在执行
  • finished    - 是否完成
  • asynchronous  - 是否异步
  • name  - 名字

  其中由 ready,executing,finished,cancelled这四个属性标示了operation对象的生命周期,也正是这几个属性使得我们的operation对象的任务能够被取消、依赖,我们将会在下一节讲到。

三、自定义Operation对象

    自定义一个operation对象之前你应该把一件事确定下来,那就是你的operation对象实现的操作是同步还异步。

    1.如果是实现同步操作的话,自定义operation类所需要做的事情就简单一点,只要覆盖main函数既可,其他的行为、特性由其的父类NSOperation来提供。具体看代码。

//  NonConcurrentOperation.h
//  IOSTest
//
//  Created by 朱国清 on 17/1/11.
//  Copyright © 2017年 朱国清. All rights reserved.
//

#import <Foundation/Foundation.h>
@interface NonConcurrentOperation : NSOperation
-(instancetype)initWithCalcCount:(NSInteger)calcCount;
@end

//  NonConcurrentOperation.m
//  IOSTest
//
//  Created by 朱国清 on 17/1/11.
//  Copyright © 2017年 朱国清. All rights reserved.
//
#import "NonConcurrentOperation.h"
@interface NonConcurrentOperation()
@property (nonatomic)NSInteger calcCount;
@end
// 同步的任务,只要实现main方法既可,其他状态由NSOperation来控制
@implementation NonConcurrentOperation
-(instancetype)initWithCalcCount:(NSInteger)calcCount{if (self = [super init]) {self.calcCount = calcCount;}return self;
}
// 由start()调用 start是入口,主要作用是更新status和调用main
// 当然调用main前也会先判断一下status
/*void start(){     // 判断 isCancel 如果已经被cancel了就直接设置isFinished为true,不调用main函数     // 执行mian      [self willChangeValueForKey:@"isFinished"];main();self.isFinished = true;[self didChangeValueForKey:@"isFinished"];}*/
-(void)main{while (!self.cancelled && self.calcCount-- > 0) {[NSThread sleepForTimeInterval:1];NSLog(@"calc[%d]",(int)self.calcCount);}
}
@end

  NonConcurrentOperation类实现了两个方法,一个是initWithCalcCount函数,这个函数传入一个代表计算任务个数的参数,并返回一个实例。可以根据你个人的需要传入不同的数据。

  另一个是main函数,这个函数用来编写你任务代码的,它是由start函数调用的。一个operation对象被添加queue后,当这个operation可以运行时(queue的线程可用/依赖都执行完成),queue就会调用operation的start方法来启动这个operation对象。

  自定义main函数时有一点值得的注意的是,在运行你的具体任务代码前应该判断一下cancelled 属性是否为真,如果为真的话就直接return 结束main函数的运行,为假是才往下执行。

  我们可以大概猜测start函数是怎么运作的,上述代码已经写出start函数的大概。相信大家都能看到懂。

  2.如果自定义的是并行任务的operation类的话,就稍微复杂一点点,得自己维护一些状态属性,并且要发送KVO通知。这次就不多说了,直接上代码。

  

//
//  ConcurrentOperation.h
//  IOSTest
//
//  Created by 朱国清 on 17/1/11.
//  Copyright © 2017年 朱国清. All rights reserved.
//

#import <Foundation/Foundation.h>@interface ConcurrentOperation : NSOperation    @end

//
//  ConcurrentOperation.m
//  IOSTest
//
//  Created by 朱国清 on 17/1/11.
//  Copyright © 2017年 朱国清. All rights reserved.
//

#import "ConcurrentOperation.h"@interface ConcurrentOperation(){BOOL executing;BOOL finished;
}
- (void)completeOperation;
@end@implementation ConcurrentOperation
-(instancetype)init{if (self=[super init]) {executing = NO;finished  = NO;}return self;
}
-(BOOL)isExecuting{return executing;
}
-(BOOL)isFinished{return finished;
}
-(BOOL)isConcurrent{return YES;
}
-(void)start{if (self.cancelled) {// 这样做才能让依赖它的operation知道已经完成了。
        [self completeOperation];return ;}[self willChangeValueForKey:@"isExecuting"];dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{[self main];});executing = YES;[self didChangeValueForKey:@"isExecuting"];
}
-(void)main{NSLog(@"operation start.");[NSThread sleepForTimeInterval:2];NSLog(@"operation end.");[self completeOperation];
}
-(void)completeOperation{[self willChangeValueForKey:@"isFinished"];[self willChangeValueForKey:@"isExecuting"];executing = NO;finished = YES;[self didChangeValueForKey:@"isExecuting"];[self didChangeValueForKey:@"isFinished"];}
@end

四、通过Operation Queues运行Operation对象

  一个operation对象,只有被添加到Operation Queue之后才能够有机会被执行的。这节我们就来学习Operation Queue对象。

  Operation Queue对象主要功能是运行与管理Operaion对象的。当我们成功创建一个Operation Queue对象后,就可以给这个queue对象添加operation

  NSOperationQueue *queue = [[NSOperationQueue alloc]init];NSBlockOperation * operationA = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"operation block A(1).");}];[queue addOperation:operationA];

  queue对象也支持直接添加block。它的内部原理是用一个operation封装block,再把这个operation对象添加到queue。

  [queue addOperationWithBlock:^{NSLog(@"wrap block .");}];

  我们还可以用下面这个函数为queue添加一组block,这个函数的第二个参数如果为true的话,会阻塞当前线程直到第一个参数指定的operations都执行完成才返回

- (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait

  当然也可以用下面这个函数阻塞当前线程直到queue的所以operation都执行完成。

- (void)waitUntilAllOperationsAreFinished

 有时候我们不需要继续执行剩下的任务了,不如正在执行时用户退出了,可以下面这个方法取消所有的operation。

  - (void)cancelAllOperations

五、手动运行Operation对象

  大部分时间我们应该不会手动运行operation对象,不过了解多一点技术总是不会错的。我们通过看代码就给知道Operation queue是怎么运行我们的operation对象的。

- (BOOL)performOperation:(NSOperation*)anOp
{BOOL        ranIt = NO;// 先判断是否准备好,是否被取消if ([anOp isReady] && ![anOp isCancelled]){    // 串行的话直接运行if (![anOp isConcurrent]){[anOp start];    }    // 并行的话开一个线程else{       [NSThread detachNewThreadSelector:@selector(start) toTarget:anOp withObject:nil];    }ranIt = YES;}else if ([anOp isCancelled]){// If it was canceled before it was started,//  move the operation to the finished state.[self willChangeValueForKey:@"isFinished"];[self willChangeValueForKey:@"isExecuting"];executing = NO;finished = YES;[self didChangeValueForKey:@"isExecuting"];[self didChangeValueForKey:@"isFinished"];// Set ranIt to YES to prevent the operation from// being passed to this method again in the future.ranIt = YES;}return ranIt;
}

  operation queue还有其他属性

  maxConcurrentOperationCount - 最大并行的operation数量,如果设置为1时就是一个串行queue。

  @property(readonly) NSUInteger operationCount  -  queue当前operation的数量

  

转载于:https://www.cnblogs.com/shuigu/p/6269366.html

NSOperation 开发相关推荐

  1. java知识体系介绍

    国内最牛七星级团队马士兵.高淇等11位十年开发经验专家录制 目 录 百战程序员Java1573题 2百战程序员介绍 3JavaSE编程基础 9第一章 初识Java 9阶段项目课程1 11第二章 数据类 ...

  2. iOS开发多线程篇—自定义NSOperation

    iOS开发多线程篇-自定义NSOperation 一.实现一个简单的tableView显示效果 实现效果展示: 代码示例(使用以前在主控制器中进行业务处理的方式) 1.新建一个项目,让控制器继承自UI ...

  3. IOS高级开发之多线程(五)NSOperation 2

    接着看NSOperation.NSOperationQueue线程间的通信: 应用场景:比如我们经常把一些耗时的操作比如下载图片放在子线程,那么当这个完成之后,我们就需要回到主线程,这个时候就需要用到 ...

  4. iOS多线程全套:线程生命周期,多线程的四种解决方案,线程安全问题,GCD的使用,NSOperation的使用(上)

    2017-07-08 remember17 Cocoa开发者社区 目的 本文主要是分享iOS多线程的相关内容,为了更系统的讲解,将分为以下7个方面来展开描述. 多线程的基本概念 线程的状态与生命周期 ...

  5. afn原理 ios_iOS开发:AFN的基本使用

    因为项目中需要用到一些第三方框架来搞定基本需求,再次总结一番.我的项目是浏览器工具,所以对网络请求处理需要做很多特别处理,这也就构成了对AFN及ASI库的深究; 1.AFN全称为:AFNetWorki ...

  6. iOS开发网络篇—NSURLConnection基本使用

    一.NSURLConnection的常用类 (1)NSURL:请求地址 (2)NSURLRequest:封装一个请求,保存发给服务器的全部数据,包括一个NSURL对象,请求方法.请求头.请求体.... ...

  7. iOS 开发中的多线程

    线程.进程 什么是线程.进程   有的人说进程就像是人的脑袋,线程就是脑袋上的头发~~.其实这么比方不算错,但是更简单的来说,用迅雷下载文件,迅雷这个程序就是一个进程,下载的文件就是一个线程,同时下载 ...

  8. iOS开发-面试总结(九)

    iOS面试指导 一 经过本人最近的面试和对面试资料的一些汇总,准备记录这些面试题,以便ios开发工程师找工作复习之用,本人希望有面试经验的同学能和我同时完成这个模块,先出面试题,然后会放出答案. 1. ...

  9. iOS网络开发中的同步、异步和请求队列

    在iOS网络编程中,我们经常会遇到线程的同步和异步问题,同时为了对异步请求更加精准丰富的控制,我们还常常在iOS中使用请求队列,下面就来谈谈iOS开发中同步.异步以及请求队列的使用方法. 1. 同步意 ...

最新文章

  1. 有什么好用的SaaS软件推荐?
  2. GitHub霸榜项目:30万字图解算法题典,超全实用资源,狂揽6000星
  3. C和C++中的##和#
  4. 小工匠聊架构-写给研发工程师的全链路压测
  5. VMwareworkstation 12安装
  6. 京东大数据研究院:智能马桶四年销量翻10倍
  7. vue 属性 watch
  8. yum安装提示yum.pid被锁定解决办法
  9. python必背100源代码-100行Python代码实现自动抢火车票(附源码)
  10. juniper防火墙命令大全(中文)
  11. 员工人事档案包括哪些内容?
  12. 【飞思卡尔】飞思卡尔摄像头算法基本方法
  13. android属性动画作用范围,Android属性动画的使用(上)
  14. Android 与Js通信报Java Exception was raised during method Invocation错误,引发的惨案
  15. 《我为什么熬夜?》系列之 倚天屠龙记
  16. 战地1 - 概念艺术
  17. MS计算轨迹的分子间作用能
  18. Java --- 线程同步和异步的区别
  19. 最小二乘法的原理及python实现
  20. 如何解决1万个并发连接,用每个客户一个线程的方法

热门文章

  1. VS2010快捷键大全----养成良好的习惯
  2. JavaScript学习——判断数据类型总结(转)
  3. 我的python之路(二):python环境安装
  4. Flutter入门进阶之旅(二)Hello Flutter
  5. 山石网科发布山石云·景产品 安全运维管理进入SaaS模式
  6. [开源 .NET 跨平台 Crawler 数据采集 爬虫框架: DotnetSpider] [四] JSON数据解析
  7. 乔布斯《我生命中的三个故事》
  8. python 版本控制及django,git的使用
  9. 出现错误ActivityManager: Warning: Activity not started
  10. arguments对象