NSOperation须要配合NSOperationQueue来实现多线程。由于默认状况下,NSOperation单独使用时系统同步执行操做,并无开辟新线程的能力,只有配合NSOperationQueue才能实现异步执行。多线程
NSOperation是一个抽象类,并不具有封装操做的能力,必须使用它的子类;并发
由于NSOperation是基于GCD的,那么使用起来也和GCD差很少,其中,NSOperation至关于GCD中的任务,而NSOperationQueue则至关于GCD中的队列。NSOperation实现多线程的使用步骤分为三步:异步
a. 建立任务:先将须要执行的操做封装到一个NSOperation对象中。学习
b. 建立队列:建立NSOperationQueue对象。spa
c. 将任务加入到队列中:而后将NSOperation对象添加到NSOperationQueue中。线程
以后呢,系统就会自动将NSOperationQueue中的NSOperation取出来,在新线程中执行操做。code
NSOperation是个抽象类,并不能封装任务。咱们只有使用它的子类来封装任务。咱们有三种方式来封装任务。对象
1 - (void)testB { 2 // 建立NSInvocationOperation对象 3 NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil]; 4 5 // 调用start方法开始执行操做 6 [op start]; 7 } 8 9 - (void)run 10 { 11 NSLog(@"当前的线程为--%@", [NSThread currentThread]); 12 }
结果:blog
2018-01-30 18:46:59.139360+0800 RAC[21774:638747] 当前的线程为--<NSThread: 0x60c000070c00>{number = 1, name = main}
BlockOperation:继承
只要BlockOperation封装的操做数 > 1,就会异步执行操做,可是不会无限制的建立线程
let blockOpe = BlockOperation() blockOpe.queuePriority = .veryHigh blockOpe.addExecutionBlock { print("BlockOperation执行了",Thread.current) } blockOpe.addExecutionBlock { print("BlockOperation2执行了",Thread.current) } blockOpe.start() //开始执行 //blockOpe.cancel() //取消
结果:
1 NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ 2 3 NSLog(@"-当前的线程为-%@",[NSThread currentThread]); 4 }]; 5 6 [op start];
结果:
在没有使用NSOperationQueue、单独使用NSBlockOperation的状况下,NSBlockOperation也是在主线程执行操做,并无开启新线程。
1 NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ 2 // 在主线程 3 NSLog(@"线程1------%@", [NSThread currentThread]); 4 }]; 5 6 // 添加额外的任务(在子线程执行) 7 [op addExecutionBlock:^{ 8 NSLog(@"线程2------%@", [NSThread currentThread]); 9 }]; 10 [op addExecutionBlock:^{ 11 NSLog(@"线程3------%@", [NSThread currentThread]); 12 }]; 13 [op addExecutionBlock:^{ 14 NSLog(@"线程4------%@", [NSThread currentThread]); 15 }]; 16 17 [op start];
结果:
blockOperationWithBlock:方法中的操做是在主线程中执行的,而addExecutionBlock:方法中的操做是在其余线程中执行的
和GCD中的并发队列、串行队列略有不一样的是:NSOperationQueue一共有两种队列:主队列、其余队列。其中其余队列同时包含了串行、并发功能。
获取主队列以及添加操做到队列,主队列是串行队列,不管是否设置最大并行数量都是在当前线程执行,不会建立新的线程
凡是添加到主队列中的任务(NSOperation),都会放到主线程中执行。
1 let queue = OperationQueue.main 2 queue.addOperation { 3 for _ in 0...50000{ 4 print("OperationQueue1执行了",Thread.current) 5 } 6 }
结果:
添加到这种队列中的任务(NSOperation),就会自动放到子线程中执行。同时包含了:串行、并发功能
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
a.
同时具有串行和并发的功能,默认状况下是并发的,能够手动设置为串行队列,经过设置最大并发数属性来更改
1 c func racsTest() { 2 let queue = OperationQueue() 3 queue.maxConcurrentOperationCount = 10 4 queue.addOperation { 5 for _ in 0...50000{ 6 print("OperationQueue1执行了",Thread.current) 7 } 8 } 9 //addOperation已经在内部执行了start方法了
结果:
a. 取消队列中的全部任务,除了正在执行的任务,一旦被取消,就不能回复以前的操做。
b. 将最大操做数的值设置为1,能够实现任务的串行效果,可是要注意的是,并非只开一条子线程(一般会开两条子线程,循环回收复用)
c. 最大并发数6之内,不要开太多,由于虽然任务是在子线程进行处理的,可是cpu处理这些过多的子线程可能会影响UI,让UI卡顿。
1 queue.maxConcurrentOperationCount=2;
1 queue.cancelAllOperations()
当前正在处于执行状态的任务是不可以暂停的,只能暂停等待的任务
1 queue.isSuspended = true //暂停队列 2 queue.isSuspended = false //恢复队列
等待Options完成
若是须要在当前线程中处理operation完成后的结果,能够使用NSOperation的waitUntilFinished方法阻塞当前线程,等待operation完成
1 [operation waitUntilFinished];
使用NSOperationQueue的waitUntilAllOperationsAreFinished方法
1 // 阻塞当前线程,等待queue的全部操做执行完毕 2 [queue waitUntilAllOperationsAreFinished];
addDependency
方法添加一个或者多个依赖的对象,只有全部依赖的对象都已经完成操做,当前NSOperation对象才会开始执行操做。另外,经过
removeDependency
方法来删除依赖对象。
1 let queue = OperationQueue() 2 //设置依赖关系 3 let blockOpe1 = BlockOperation() 4 blockOpe1.addExecutionBlock { 5 print("blockOpe1执行了") 6 } 7 let blockOpe2 = BlockOperation() 8 blockOpe2.addExecutionBlock { 9 print("blockOpe2执行了") 10 } 11 blockOpe1.addDependency(blockOpe2) 12 queue.addOperation(blockOpe1) 13 queue.addOperation(blockOpe2) 14 // 能够看出,先执行blockOpe2,再执行blockOpe1 15
结果:
默认全部operation都拥有“普通”优先级,不过能够经过setQueuePriority:方法来提高或下降operation对象的优先级。
1 let queue = OperationQueue() 2 queue.maxConcurrentOperationCount = 3 3 4 let blockOpe = BlockOperation() 5 blockOpe.addExecutionBlock { 6 print("blockOpe------------>执行了") 7 } 8 blockOpe.queuePriority = .veryHigh 9 10 let blockOpe1 = BlockOperation() 11 blockOpe1.addExecutionBlock { 12 print("blockOpe1------------>执行了") 13 } 14 blockOpe1.queuePriority = .low 15 16 queue.addOperation(blockOpe1) 17 queue.addOperation(blockOpe)
结果:
1 // 定义一个继承自NSOperation的子类,重写main方法 2 // YSCOperation.h 3 #import <Foundation/Foundation.h> 4 5 @interface YSCOperation : NSOperation 6 7 @end 8 9 10 // YSCOperation.m 11 12 #import "YSCOperation.h" 13 14 @implementation YSCOperation 15 /** 16 * 须要执行的任务 17 */ 18 19 - (void)main 20 { 21 for (int i = 0; i < 2; ++i) { 22 NSLog(@"--i---%@",[NSThread currentThread]); 23 } 24 } 25 26 @end 27 28 29 30 // 导入头文件YSCOperation.h 31 // 建立YSCOperation 32 YSCOperation *op1 = [[YSCOperation alloc] init]; 33 34 [op1 start];
结果:
--0---<NSThread: 0x6080000779c0>{number = 1, name = main} --1---<NSThread: 0x6080000779c0>{number = 1, name = main}
在没有使用NSOperationQueue、单独使用自定义子类的状况下,是在主线程执行操做,并无开启新线程。