李明杰讲的简单易懂:http://blog.csdn.net/q199109106q/article/details/8566222
1. NSOperation
NSOperation是个抽象类,对GCD进行的封装,并不具备封装操作的能力,必须使⽤它的子类。
NSOperation的作⽤:配合使用NSOperation和NSOperationQueue也能实现多线程编程。
// 开始对象运行
- (void)start;
// 同上,如果继承NSOperation,重写该方法。
- (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 NS_AVAILABLE(10_8, 7_0);
// 是不是可执行
@property (readonly, getter=isReady) BOOL ready;
// 添加依赖
- (void)addDependency:(NSOperation *)op;
// 取消依赖
- (void)removeDependency:(NSOperation *)op;
// 依赖对象数组
@property (readonly, copy) NSArray<NSOperation *> *dependencies;
// 优先级
@property NSOperationQueuePriority queuePriority;
// 对象完成之后的操作
@property (nullable, copy) void (^completionBlock)(void);
// 阻塞当前线程
- (void)waitUntilFinished;
// 线程优先级
@property double threadPriority;
// 操作名字
@property (nullable, copy) NSString *name;
// 服务质量,就是枚举
@property NSQualityOfService qualityOfService;
注意:NSOperation添加到queue之后,绝对不要再修改NSOperation对象的状态。因为NSOperation对象可能会在任何时候运行,因此改变NSOperation对象的依赖或数据会产生不利的影响。你只能查看NSOperation对象的状态, 比如是否正在运行、等待运行、已经完成等。
2. NSOperation的子类
使用NSOperation⼦类的方式有3种:
1. NSInvocationOperation
2. NSBlockOperation
3. 自定义子类继承NSOperation,实现内部相应的⽅法(感觉没必要)
/**
注意:NSOperation对象默认在主队列,主线程中执行,只有添加到队列中才会开启新的线程。
即默认情况下,如果操作没有放到队列中queue中,都是同步执行。
只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作
*/
NSBlockOperation
// 实例化NSBlockOperation
+ (instancetype)blockOperationWithBlock:(void (^)(void))block;
// 添加执行代码块
- (void)addExecutionBlock:(void (^)(void))block;
// 获取执行代码块
@property (readonly, copy) NSArray<void (^)(void)> *executionBlocks;
// 只要NSBlockOperation的block > 1,就会在主队列,异步执行操作
// addExecutionBlock 必须添加到 [blockOperation start] 之前
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"NSBlockOperation--test1--%@",[NSThread currentThread]);
}];
[blockOperation addExecutionBlock:^{
NSLog(@"NSBlockOperation--test2--%@",[NSThread currentThread]);
}];
[blockOperation addExecutionBlock:^{
NSLog(@"NSBlockOperation--test3--%@",[NSThread currentThread]);
}];
[blockOperation start];
NSInvocationOperation
// 生成对象,target:执行sel的对象 sel:方法 arg:传给sel的参数对象
- (nullable instancetype)initWithTarget:(id)target selector:(SEL)sel object:(nullable id)arg;
// 下面有待研究
- (instancetype)initWithInvocation:(NSInvocation *)inv;
@property (readonly, retain) NSInvocation *invocation;
@property (nullable, readonly, retain) id result;
//创建操作对象,封装要执行的任务
NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(test) object:nil];
//执行操作
[invocationOperation start];
3. NSOperationQueue
// 添加NSOperation对象
- (void)addOperation:(NSOperation *)op;
// 添加NSOperation对象数组,如果wait == \(^o^)/YES!则阻塞当前线程,等待操作完成
- (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait;
// 添加block,直接生成一个NSOperation对象
- (void)addOperationWithBlock:(void (^)(void))block;
// 添加的操作数组
@property (readonly, copy) NSArray<__kindof NSOperation *> *operations;
// 添加的操作个数
@property (readonly) NSUInteger operationCount;
// 最大线程数
@property NSInteger maxConcurrentOperationCount;
// 是否暂停 YES 暂停
@property (getter=isSuspended) BOOL suspended;
// 队列名字
@property (nullable, copy) NSString *name;
@property NSQualityOfService qualityOfService;
@property (nullable, assign /* actually retain */) dispatch_queue_t underlyingQueue NS_AVAILABLE(10_10, 8_0);
// 取消所有操作
- (void)cancelAllOperations;
// 等待所有操作完成,当前线程处于阻塞状态
- (void)waitUntilAllOperationsAreFinished;
// 获取当前队列
+ (nullable NSOperationQueue *)currentQueue;
// 获取主队列
+ (NSOperationQueue *)mainQueue;
NSOperation和NSOperationQueue实现多线程的具体步骤:
1. 先将需要执行的操作封装到一个NSOperation对象中
2. 然后将NSOperation对象添加到NSOperationQueue中
3. 系统会⾃动将NSOperationQueue中的NSOperation取出来
4. 将取出的NSOperation封装的操作放到⼀条新线程中执⾏
// 队列是并行队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *blockOperation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"NSBlockOperation--test1--%@",[NSThread currentThread]);
}];
NSBlockOperation *blockOperation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"NSBlockOperation--test2--%@",[NSThread currentThread]);
}];
NSBlockOperation *blockOperation3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"NSBlockOperation--test3--%@",[NSThread currentThread]);
}];
NSBlockOperation *blockOperation4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"NSBlockOperation--test4--%@",[NSThread currentThread]);
}];
// 添加代码块操作
[queue addOperationWithBlock:^{
NSLog(@"[%s]%d", __func__, __LINE__);
}];
[queue addOperations:@[blockOperation1, blockOperation2, blockOperation3, blockOperation4] waitUntilFinished:NO];
注意:NSOperation添加到queue之后,通常短时间内就会得到运行。但是如果存在依赖,或者整个queue被暂停等原因,也可能需要等待。
4.添加NSOperation的依赖对象
1.
当某个NSOperation对象依赖于其它NSOperation对象的完成时,就可以通过addDependency方法添加一个或者多个依赖的对象,只有所有依赖的对象都已经完成操作,当前NSOperation对象才会开始执行操作。另外,通过removeDependency方法来删除依赖对象。
[operation2 addDependency:operation1];
[operation2 removeDependency:operation1];
依赖关系不局限于相同queue中的NSOperation对象,NSOperation对象会管理自己的依赖, 因此完全可以在不同的queue之间的NSOperation对象创建依赖关系
唯一的限制是不能创建环形依赖,比如A依赖B,B依赖A,这是错误的
2.
依赖关系会影响到NSOperation对象在queue中的执行顺序,看下面的例子:
1> 没有设置依赖关系
NSBlockOperation *block1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"block1--%@", [NSThread currentThread]);
}];
NSBlockOperation *block2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"block2--%@", [NSThread currentThread]);
}];
NSBlockOperation *block3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"block3--%@", [NSThread currentThread]);
}];
NSBlockOperation *block4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"block4--%@", [NSThread currentThread]);
}];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:block1];
[queue addOperation:block2];
[queue addOperation:block3];
[queue addOperation:block4];
打印信息:
2016-04-07 20:23:52.460 Test[1049:48861] block1--<NSThread: 0x7fd6bc000450>{number = 2, name = (null)}
2016-04-07 20:23:52.558 Test[1049:48859] block2--<NSThread: 0x7fd6b9f0e350>{number = 3, name = (null)}
2016-04-07 20:23:52.560 Test[1049:48886] block3--<NSThread: 0x7fd6b9c233b0>{number = 4, name = (null)}
2016-04-07 20:23:52.563 Test[1049:48851] block4--<NSThread: 0x7fd6b9c25020>{number = 5, name = (null)}
2> 设置了依赖关系
NSBlockOperation *block1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"block1--%@", [NSThread currentThread]);
}];
NSBlockOperation *block2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"block2--%@", [NSThread currentThread]);
}];
NSBlockOperation *block3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"block3--%@", [NSThread currentThread]);
}];
NSBlockOperation *block4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"block4--%@", [NSThread currentThread]);
}];
[block1 addDependency:block4];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:block1];
[queue addOperation:block2];
[queue addOperation:block3];
[queue addOperation:block4];
打印信息:
2016-04-07 20:25:09.799 Test[1074:51008] block4--<NSThread: 0x7fceead311d0>{number = 4, name = (null)}
2016-04-07 20:25:09.799 Test[1074:50994] block2--<NSThread: 0x7fceeaf3c4a0>{number = 2, name = (null)}
2016-04-07 20:25:09.799 Test[1074:51002] block3--<NSThread: 0x7fceeaf3a510>{number = 3, name = (null)}
2016-04-07 20:25:09.801 Test[1074:50994] block1--<NSThread: 0x7fceeaf3c4a0>{number = 2, name = (null)}