1. NSOperation简介
NSOperation
是苹果提供给我们的一套二十八线程化解方案。实际上NSOperation是依靠GCD越来越高级中学一年级层的卷入,但是比GCD更简便易行易用、代码可读性也越来越高。
NSOperation需求合作NSOperationQueue来达成四线程。因为在暗许情状下,NSOperation单独采纳时系统一齐实行操作,并没有开拓新线程的力量,独有NSOperationQueue技艺实现异步实践。
NSOperation是依据GCD的,那么使用起来也和GCD大致,其中,NSOperation也正是GCD中的职分,而NSOperationQueue则也等于GCD中的队列。NSOperation完成多线程的行使手续分为三步:
- 创造任务:先将须求实施的操作封装到叁个NSOperation对象中;
- 创立队列:制造NSOperationQueue对象;
- 将任务参预到行列中:然后将NSOperation对象增添到NSOperationQueue中。
未来,系统就会活动将NSOperationQueue中的NSOperation抽出来,在新野县城中施行操作。
– – – – – – – – –
上面大家来读书下NSOperation和NSOperationQueue的中央接纳 – – – – – –
一、什么是NSOperation?
NSOperation是苹果提供的一套八线程消除方案。实际上NSOperation是基于GCD更加高级中学一年级层的包裹,不过比GCD更加的面向对象、代码可读性越来越高、可控性越来越强,相当的屌的是加盟了操作注重。
暗中同意景况下,NSOperation单独选择时只能同步实施操作,并未有开垦新线程的力量,独有合作NSOperationQueue手艺达成异步实行。讲到这里,我们轻易窥见GCD和NSOperation完结的艺术很像,其实那更疑似废话,NSOperation自个儿就是依赖GCD的包装,NSOperation相当于GCD中的职责,而NSOperationQueue则相当于GCD中的队列,前边《iOS八线程支付之GCD(上篇)》中一度演说过GCD的本来面目:开垦者要做的只是概念想举行的任务并追加到合适的Dispatch
Queue中。那样大家也可说NSOperation的本质便是:定义想举办的职务(NSOperation)并追加到至极的NSOperationQueue中。
2. NSOperation的宗旨选用
二、NSOperation使用
1、创造任务
NSOperation是七个虚幻的基类,表示四个独门的持筹握算单元,可感到子类提供有用且线程安全的树立情状,优先级,注重和撤除等操作。但它不可能向来用来封装义务,只可以通过它的子类来封装,一般的大家得以应用:NSBlockOperation、NSInvocationOperation也许定义承接自NSOperation的子类,通过落到实处内部相应的措施来封装职务。
(1)NSInvocationOperation
- (void)invocationOperation{
NSLog(@"start - %@",[NSThread currentThread]);
// 创建NSInvocationOperation对象
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(testRun) object:nil];
// 调用start方法开始执行操作
[op start];
NSLog(@"end - %@",[NSThread currentThread]);
}
- (void)testRun{
NSLog(@"invocationOperation -- %@", [NSThread currentThread]);
}
实施结果:
2017-07-14 13:43:59.327 beck.wang[10248:1471363] start - <NSThread: 0x6100000614c0>{number = 1, name = main}
2017-07-14 13:43:59.328 beck.wang[10248:1471363] invocationOperation -- <NSThread: 0x6100000614c0>{number = 1, name = main}
2017-07-14 13:43:59.328 beck.wang[10248:1471363] end - <NSThread: 0x6100000614c0>{number = 1, name = main}
解析:单独行使NSInvocationOperation的情况下,NSInvocationOperation在主线程同步实践操作,并从未开启新线程。
(2)NSBlockOperation
- (void)blockOperation{
NSLog(@"start - %@",[NSThread currentThread]);
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperation--%@", [NSThread currentThread]);
}];
NSLog(@"end - %@",[NSThread currentThread]);
[op start];
}
打印结果:
2017-07-14 13:49:25.436 beck.wang[10304:1476355] start - <NSThread: 0x6100000653c0>{number = 1, name = main}
2017-07-14 13:49:25.436 beck.wang[10304:1476355] end - <NSThread: 0x6100000653c0>{number = 1, name = main}
2017-07-14 13:49:25.436 beck.wang[10304:1476355] blockOperation--<NSThread: 0x6100000653c0>{number = 1, name = main}
剖判:单独选取NSBlockOperation的景观下,NSBlockOperation也是在主线程实施操作,未有展开新线程。
值得注意的是:NSBlockOperation还提供了贰个方法addExecutionBlock:
,通过addExecutionBlock:
就足感觉NSBlockOperation增添额外的操作,那个额外的操作就能够在任何线程并发施行。
- (void)blockOperation{
NSLog(@"start - %@",[NSThread currentThread]);
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperation--%@", [NSThread currentThread]);
}];
// 添加额外任务(在子线程执行)
[op addExecutionBlock:^{
NSLog(@"addTask1---%@", [NSThread currentThread]);
}];
[op addExecutionBlock:^{
NSLog(@"addTask2---%@", [NSThread currentThread]);
}];
[op addExecutionBlock:^{
NSLog(@"addTask3---%@", [NSThread currentThread]);
}];
NSLog(@"end - %@",[NSThread currentThread]);
[op start];
}
打字与印刷结果:
2017-07-14 13:57:02.009 beck.wang[10351:1482603] start - <NSThread: 0x60000007cdc0>{number = 1, name = main}
2017-07-14 13:57:02.009 beck.wang[10351:1482603] end - <NSThread: 0x60000007cdc0>{number = 1, name = main}
2017-07-14 13:57:02.010 beck.wang[10351:1482603] blockOperation--<NSThread: 0x60000007cdc0>{number = 1, name = main}
2017-07-14 13:57:02.010 beck.wang[10351:1482642] addTask1---<NSThread: 0x618000260e00>{number = 3, name = (null)}
2017-07-14 13:57:02.010 beck.wang[10351:1482645] addTask3---<NSThread: 0x600000263200>{number = 5, name = (null)}
2017-07-14 13:57:02.010 beck.wang[10351:1482643] addTask2---<NSThread: 0x610000264600>{number = 4, name = (null)}
深入分析:blockOperationWithBlock职分在主线程中实践,addExecutionBlock的天职在新开线程中实行。
(3)自定义NSOperation子类--重写main方法就可以
.h
@interface ZTOperation : NSOperation
@end
.m
@implementation ZTOperation
- (void)main{
// 在这里可以自定义任务
NSLog(@"ZTOperation--%@",[NSThread currentThread]);
}
@end
ViewController
ZTOperation *zt = [[ZTOperation alloc] init];
[zt start];
打字与印刷结果:
2017-07-14 14:05:58.824 beck.wang[10389:1490955] ZTOperation--<NSThread: 0x60000007a940>{number = 1, name = main}
深入分析:职务在主线程中进行,不开启新线程。
2、创立队列
NSOperationQueue
一齐有三种队列:主队列、其余队列。当中任何队列同期涵盖了串行、并发效率,通过安装最大并发数maxConcurrentOperationCount来贯彻串行、并发!
(1)主队列 — 职分在主线程中实施
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
(2)其余队列 — 职分在子线程中施行
NSOperationQueue *elseQueue = [[NSOperationQueue alloc] init];
3、NSOperation + NSOperationQueue (义务增加到行列)
// 添加单个操作:
- (void)addOperation:(NSOperation *)op;
// 添加多个操作:
- (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait NS_AVAILABLE(10_6, 4_0);
// 添加block操作:
- (void)addOperationWithBlock:(void (^)(void))block NS_AVAILABLE(10_6, 4_0);
代码示例:
- (void)addOperationToQueue
{
NSLog(@"start - %@",[NSThread currentThread]);
// 创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 创建NSInvocationOperation
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(testRun) object:nil];
// 创建NSBlockOperation
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"task002 -- %@", [NSThread currentThread]);
}];
// 添加操作到队列中: addOperation:
[queue addOperation:op1];
[queue addOperation:op2];
// 添加操作到队列中:addOperationWithBlock:
[queue addOperationWithBlock:^{
NSLog(@"task003-----%@", [NSThread currentThread]);
}];
NSLog(@"end - %@",[NSThread currentThread]);
}
- (void)testRun{
NSLog(@"task001 -- %@", [NSThread currentThread]);
}
打字与印刷结果:
2017-07-14 14:39:51.669 beck.wang[10536:1516641] start - <NSThread: 0x610000077640>{number = 1, name = main}
2017-07-14 14:39:51.670 beck.wang[10536:1516641] end - <NSThread: 0x610000077640>{number = 1, name = main}
2017-07-14 14:39:51.670 beck.wang[10536:1516686] task003-----<NSThread: 0x600000077200>{number = 3, name = (null)}
2017-07-14 14:39:51.670 beck.wang[10536:1516689] task002 -- <NSThread: 0x61800007e080>{number = 5, name = (null)}
2017-07-14 14:39:51.670 beck.wang[10536:1516687] task001 -- <NSThread: 0x61000007e1c0>{number = 4, name = (null)}
解析:开启新线程,并发推行。
2.1 成立职务
NSOperation是个抽象类,并不可能封装职分。我们独有利用它的子类来封装职务,大家有三种方法来封装任务。
a. 使用子类NSInvocationOperation
b. 使用子类NSBlockOperation
c. 定义承接自NSOperation的子类,通过完毕内部相应的议程来封装职务。
在不应用NSOperationQueue,单独行使NSOperation的情状下系统一齐实行操作,上边大家询问一下:
三、NSOperationQueue管理
1、队列的裁撤、暂停、恢复生机
– (void)cancel;
NSOperation提供的艺术,可打消单个操作
–
(void)cancelAllOperations;
NSOperationQueue提供的法子,能够收回队列的有所操作
–
(void)setSuspended:(BOOL)b;
可安装职务的暂停和还原,YES代表暂停队列,NO代表复苏队列
–
(BOOL)isSuspended; 剖断暂停状态
暂停或吊销并不可能使正在实践的操作立刻暂停或撤销,而是当前操作实践完后不再推行新的操作。两者的差别在于暂停操作之后还能回复操作,继续向下进行;而撤回操作之后,全数的操作就清空了,无法再跟着执行剩下的操作。
2、最大并发数 maxConcurrentOperationCount
maxConcurrentOperationCount = -
1 表示不限定,暗中同意并发实行;
maxConcurrentOperationCount =
1 意味着最大并发数为1,串行实施;
maxConcurrentOperationCount >
([count] > =1) 代表并发实践,min[count,系统限制]。
代码示例:
- (void)operationQueue
{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 设置最大并发操作数
// queue.maxConcurrentOperationCount = - 1; // 并发执行
// queue.maxConcurrentOperationCount = 1; // 同步执行
queue.maxConcurrentOperationCount = 2; // 并发执行
[queue addOperationWithBlock:^{
NSLog(@"task1-----%@", [NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"task2-----%@", [NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"task3-----%@", [NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"task4-----%@", [NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"task5-----%@", [NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"task6-----%@", [NSThread currentThread]);
}];
}
打字与印刷结果:
// queue.maxConcurrentOperationCount = - 1
2017-07-14 15:28:39.554 beck.wang[10772:1557342] task2-----<NSThread: 0x61800006d340>{number = 4, name = (null)}
2017-07-14 15:28:39.554 beck.wang[10772:1557358] task3-----<NSThread: 0x6080000751c0>{number = 5, name = (null)}
2017-07-14 15:28:39.554 beck.wang[10772:1557359] task4-----<NSThread: 0x610000071c00>{number = 6, name = (null)}
2017-07-14 15:28:39.554 beck.wang[10772:1557339] task5-----<NSThread: 0x60000006ea40>{number = 7, name = (null)}
2017-07-14 15:28:39.554 beck.wang[10772:1557340] task1-----<NSThread: 0x608000073500>{number = 3, name = (null)}
2017-07-14 15:28:39.554 beck.wang[10772:1557360] task6-----<NSThread: 0x610000071c80>{number = 8, name = (null)}
// 分析:线程数为6,并发执行
-----------------------------------分割线----------------------------------------------
// queue.maxConcurrentOperationCount = 1
2017-07-14 15:27:04.365 beck.wang[10743:1555231] task1-----<NSThread: 0x60800007c880>{number = 3, name = (null)}
2017-07-14 15:27:04.365 beck.wang[10743:1555231] task2-----<NSThread: 0x60800007c880>{number = 3, name = (null)}
2017-07-14 15:27:04.365 beck.wang[10743:1555231] task3-----<NSThread: 0x60800007c880>{number = 3, name = (null)}
2017-07-14 15:27:04.365 beck.wang[10743:1555231] task4-----<NSThread: 0x60800007c880>{number = 3, name = (null)}
2017-07-14 15:27:04.366 beck.wang[10743:1555231] task5-----<NSThread: 0x60800007c880>{number = 3, name = (null)}
2017-07-14 15:27:04.366 beck.wang[10743:1555231] task6-----<NSThread: 0x60800007c880>{number = 3, name = (null)}
// 分析:线程个数为1,同步执行
-----------------------------------分割线----------------------------------------------
// queue.maxConcurrentOperationCount = 2
2017-07-14 15:18:26.162 beck.wang[10715:1548342] task2-----<NSThread: 0x608000079740>{number = 4, name = (null)}
2017-07-14 15:18:26.162 beck.wang[10715:1548344] task1-----<NSThread: 0x6100000770c0>{number = 3, name = (null)}
2017-07-14 15:18:26.162 beck.wang[10715:1548342] task4-----<NSThread: 0x608000079740>{number = 4, name = (null)}
2017-07-14 15:18:26.162 beck.wang[10715:1548344] task3-----<NSThread: 0x6100000770c0>{number = 3, name = (null)}
2017-07-14 15:18:26.162 beck.wang[10715:1548342] task5-----<NSThread: 0x608000079740>{number = 4, name = (null)}
2017-07-14 15:18:26.163 beck.wang[10715:1548344] task6-----<NSThread: 0x6100000770c0>{number = 3, name = (null)}
// 分析:线程个数为2,并发执行
很扎眼,通过安装maxConcurrentOperationCount就能够落到实处产出、串行功能是或不是比GCD轻易多了!
3、操作依赖
NSOperation中我们可感觉操作分解为多少个小的任务,通过加多他们中间的看重关系实行操作,那么些平常用到!那也是NSOperation吸引人的地点,无需像GCD那样选用复杂的代码达成,addDependency就足以解决!
- (void)addDependency
{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
sleep(2);
NSLog(@"task1-----%@", [NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"task2-----%@", [NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"task3-----%@", [NSThread currentThread]);
}];
// op2依赖于op1 执行顺序op1->op2 必须放在[添加操作队列]之前
[op2 addDependency:op1];
// 忌循环依赖 op2已经依赖于op1,切不可再让op1依赖于op2,形成循环依赖
//[op1 addDependency:op2];
// 添加操作队列
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];
}
打印结果:
2017-07-14 15:46:02.011 beck.wang[10854:1571574] task3-----<NSThread: 0x61800006d740>{number = 3, name = (null)}
2017-07-14 15:46:04.085 beck.wang[10854:1571596] task1-----<NSThread: 0x60000006f040>{number = 4, name = (null)}
2017-07-14 15:46:04.085 beck.wang[10854:1571574] task2-----<NSThread: 0x61800006d740>{number = 3, name = (null)}
深入分析:task2一定在task1前面实践,因为实行task1前设置了线程等待2s,全体task3最早试行。
4、操作优先级
NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8
5、操作的监听
能够监听一个操作是不是进行实现,如下载图片,须求在下载第一张图片后才具下载第二张图纸,这里就足以设置监听。
- (void)addListing{
NSOperationQueue *queue=[[NSOperationQueue alloc]init];
NSBlockOperation *operation=[NSBlockOperation blockOperationWithBlock:^{
for (int i=0; i<3; i++) {
NSLog(@"下载图片1-%@",[NSThread currentThread]);
}
}];
// 监听操作的执行完毕
operation.completionBlock=^{
// 继续进行下载图片操作
NSLog(@"--下载图片2--");
};
[queue addOperation:operation];
}
实施结果:
2017-07-14 16:21:43.833 beck.wang[10930:1597954] 下载图片1-<NSThread: 0x61800007a340>{number = 3, name = (null)}
2017-07-14 16:21:43.834 beck.wang[10930:1597954] 下载图片1-<NSThread: 0x61800007a340>{number = 3, name = (null)}
2017-07-14 16:21:43.834 beck.wang[10930:1597954] 下载图片1-<NSThread: 0x61800007a340>{number = 3, name = (null)}
2017-07-14 16:21:43.834 beck.wang[10930:1597955] --下载图片2--
剖判:下载图片1做到后才会实施下载图片2,这里就像知识点3中的加多依赖。
留在最终的话:十六线程不只是有GCD!即使你还不曾用过NSOperation,还说什么样啊?赶紧演练起来!当然他们各有各的运用意况,存在即成立!iOS八线程的二种技术GCD、NSThread、NSOperation就都介绍完了,须要通晓 GCD、NSThread的能够回头看看作者事先的博客。
2.2 使用子类NSInvocationOperation
// 1.创建NSInvocationOperation对象
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
// 2.调用start方法开始执行操作
[op start];
- (void)run
{
NSLog(@"------%@", [NSThread currentThread]);
}
输出结果:
<NSThread: 0x604000260b00>{number = 1, name = main}
从中能够观看,在未有利用NSOperationQueue,单独行使NSOperation的景况下,NSInvocationOperation是在当下线程中施行操作,并从未开创新的线程。因为,当前线程是主线程,所以打印出的是主线程。
2.3 使用NSBlockOperation
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
// 在主线程
NSLog(@"------%@", [NSThread currentThread]);
}];
[op start];
输出结果:
<NSThread: 0x604000260b00>{number = 1, name = main}
从中能够看出,在没有运用NSOperationQueue,单独行使NSOperation的气象下,NSBlockOperation是在主线程中实行操作,并未开革新的线程。
不过NSBlockOperation还提供了一个艺术
addExecutionBlock:,通过那一个点子就足认为NSBlockOperation增添额外的操作,这么些额外的操作就能在别的线程中并发实施。
出口结果
NSOperation[1326:87276] 3 - <NSThread: 0x6000002715c0>{number = 4, name = (null)}
NSOperation[1326:87282] 1 - <NSThread: 0x604000271780>{number = 3, name = (null)}
NSOperation[1326:87200] <NSThread: 0x60000006c6c0>{number = 1, name = main}
NSOperation[1326:87274] 2 - <NSThread: 0x6000002714c0>{number = 5, name = (null)}
大家能够看到,职分都是出新施行的,NSBlockOperation中的职分是在主线程中实行的,addExecutionBlock是在新线程中实行的。
2.4 自定义继承NSOperation的子类
WCEOperation.h
#import <Foundation/Foundation.h>
@interface WCEOperation : NSOperation
@end
WCEOperation.m
#import "WCEOperation.h"
@implementation WCEOperation
// 需要执行的任务
-(void)main{
for (NSInteger i = 0; i < 5; i++) {
NSLog(@"%@",[NSThread currentThread]);
}
}
@end
在应用的时候,导入这几个文件
WCEOperation *operation = [[WCEOperation alloc] init];
[operation start];
输出结果:
2017-12-11 22:53:42.126565+0800 NSOperation[1388:90762] <NSThread: 0x60400007fe40>{number = 1, name = main}
2017-12-11 22:53:42.126803+0800 NSOperation[1388:90762] <NSThread: 0x60400007fe40>{number = 1, name = main}
2017-12-11 22:53:42.126946+0800 NSOperation[1388:90762] <NSThread: 0x60400007fe40>{number = 1, name = main}
2017-12-11 22:53:42.127171+0800 NSOperation[1388:90762] <NSThread: 0x60400007fe40>{number = 1, name = main}
2017-12-11 22:53:42.127309+0800 NSOperation[1388:90762] <NSThread: 0x60400007fe40>{number = 1, name = main}
大家得以看出,在尚未采纳NSOperationQueue的场地下,任务都以在主线程中实施的,并未展开新的线程。
3. NSOperationQueue的主干接纳
和GCD中的并发队列、串行队列略有差异的是:NSOperationQueue
一共有三种队列:主队列、别的队列。个中任何队列相同的时候涵盖了串行、并发效能。上面是主队列、别的队列的主导创造方法和特色。
– 主队列:
凡是增添到主队列中的职务(NSOperation),都会安置主线程中实行
NSOperationQueue *queue = [NSOperationQueue mainQueue];
– 别的队列(非主队列)
· 增添到这种队列中的职务(NSOperation),就能够自动放到子线程中实施
· 同一时间含有了:串行、并发功效
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
4. 将任务出席到行列中
前面说了,NSOperation须求相称NSOperationQueue来落成十六线程,那么大家必要将成立好的天职加入到行列中去,总共有两种艺术:
a: – (void)addOperation:(NSOperation *)op;
亟需先创立职分,再将成立好的义务加入到开创好的队列中去
NSOperationQueue *opQueue = [[NSOperationQueue alloc] init];
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@ - 1",[NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@ - 2",[NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@ - 3",[NSThread currentThread]);
}];
NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@ - 4",[NSThread currentThread]);
}];
NSBlockOperation *op5 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@ - 5",[NSThread currentThread]);
}];
[opQueue addOperation:op1];
[opQueue addOperation:op2];
[opQueue addOperation:op3];
[opQueue addOperation:op4];
[opQueue addOperation:op5];
运营结果:
2017-12-11 23:07:19.203418+0800 NSOperation[1468:97665] <NSThread: 0x60000046ac80>{number = 4, name = (null)} - 4
2017-12-11 23:07:19.203429+0800 NSOperation[1468:97664] <NSThread: 0x604000463300>{number = 6, name = (null)} - 1
2017-12-11 23:07:19.203439+0800 NSOperation[1468:97666] <NSThread: 0x60000046a980>{number = 5, name = (null)} - 2
2017-12-11 23:07:19.203867+0800 NSOperation[1468:97665] <NSThread: 0x60000046ac80>{number = 4, name = (null)} - 5
2017-12-11 23:07:19.204450+0800 NSOperation[1468:97667] <NSThread: 0x604000463280>{number = 3, name = (null)} - 3
能够见见,NSOperation和NSOperationQueue结合后能够展开新线程,并发实施。
b. – (void)addOperationWithBlock:(void(^)void)block;
不用创造职务,在block中加上职分,直接将职分block加入到行列中。
NSOperationQueue *opQueue = [[NSOperationQueue alloc] init];
[opQueue addOperationWithBlock:^{
NSLog(@"1 - - %@",[NSThread currentThread]);
}];
[opQueue addOperationWithBlock:^{
NSLog(@"2 - - %@",[NSThread currentThread]);
}];
[opQueue addOperationWithBlock:^{
NSLog(@"3 - - %@",[NSThread currentThread]);
}];
[opQueue addOperationWithBlock:^{
NSLog(@"4 - - %@",[NSThread currentThread]);
}];
[opQueue addOperationWithBlock:^{
NSLog(@"5 - - %@",[NSThread currentThread]);
}];
运转结果:
2017-12-11 23:17:38.951881+0800 NSOperation[1510:102617] 2 - - <NSThread: 0x600000275400>{number = 4, name = (null)}
2017-12-11 23:17:38.951884+0800 NSOperation[1510:102615] 4 - - <NSThread: 0x6040004655c0>{number = 6, name = (null)}
2017-12-11 23:17:38.951889+0800 NSOperation[1510:102616] 1 - - <NSThread: 0x604000465540>{number = 3, name = (null)}
2017-12-11 23:17:38.951917+0800 NSOperation[1510:102619] 3 - - <NSThread: 0x604000465580>{number = 5, name = (null)}
2017-12-11 23:17:38.952182+0800 NSOperation[1510:102614] 5 - - <NSThread: 0x6000002754c0>{number = 7, name = (null)}
大家能够看到,都以在新的线程中推行的,并且是出新推行。
5. 说了算串行实践和并行实践的基本点
NSOperationQueue创造的任何队列同期负有串行、并发作用,上面展现了并发功用,那么她的串行作用是怎么落实的?
此地就需求使用一个器重参数:maxConcurrentOperationCount –
最大并发数。约等于最大还要施行的天职位数量,一般2-3,大于5未来,尽管是在子线程中管理,可是cpu管理过多的子线程,也会有望影响主线程。
- 暗许景况下为 -1,表示不进行限制,默感觉并发试行
- 当maxConcurrentOperationCount为1时,进行串行实践。
- 当maxConcurrentOperationCount大于1时,实行并发施行,当然那么些值不应抢先系统限制,不然正是本人安装一个相当的大的值,系统也会活动调治。
或然刚刚这些例子,大家只设置NSOperationQueue的最大并发数为1
NSOperationQueue *opQueue = [[NSOperationQueue alloc] init];
opQueue.maxConcurrentOperationCount = 1;
[opQueue addOperationWithBlock:^{
NSLog(@"1 - - %@",[NSThread currentThread]);
}];
[opQueue addOperationWithBlock:^{
NSLog(@"2 - - %@",[NSThread currentThread]);
}];
[opQueue addOperationWithBlock:^{
NSLog(@"3 - - %@",[NSThread currentThread]);
}];
[opQueue addOperationWithBlock:^{
NSLog(@"4 - - %@",[NSThread currentThread]);
}];
[opQueue addOperationWithBlock:^{
NSLog(@"5 - - %@",[NSThread currentThread]);
}];
输出结果:
2017-12-11 23:22:30.824859+0800 NSOperation[1535:105237] 1 - - <NSThread: 0x600000275cc0>{number = 3, name = (null)}
2017-12-11 23:22:30.825228+0800 NSOperation[1535:105238] 2 - - <NSThread: 0x600000275d00>{number = 4, name = (null)}
2017-12-11 23:22:30.825614+0800 NSOperation[1535:105238] 3 - - <NSThread: 0x600000275d00>{number = 4, name = (null)}
2017-12-11 23:22:30.826585+0800 NSOperation[1535:105250] 4 - - <NSThread: 0x6000002756c0>{number = 5, name = (null)}
2017-12-11 23:22:30.826851+0800 NSOperation[1535:105250] 5 - - <NSThread: 0x6000002756c0>{number = 5, name = (null)}
能够阅览,当最大并发数为1的时候,职分是按顺序串行试行的,当最大并发数为2时,职分是出新实施的,何况展开线程数量是由系统调控的。
6. 操作信赖
NSOperation和NSOperationQueue最迷惑认得地方是它能丰盛操作之间的依赖关系。比方有A和B多少个操作,当中A实施完操作,B工夫实践操作,那么就需求让B注重于A:
NSOperationQueue *opQueue = [[NSOperationQueue alloc] init];
NSBlockOperation *opA = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"我是opA,我先执行 - %@",[NSThread currentThread]);
}];
NSBlockOperation *opB = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"我是opB,我后执行 - %@",[NSThread currentThread]);
}];
[opB addDependency:opA];
[opQueue addOperation:opB];
[opQueue addOperation:opA];
输出结果:
2017-12-11 23:31:23.494225+0800 NSOperation[1569:109435] 我是opA,我先执行 - <NSThread: 0x604000079ec0>{number = 3, name = (null)}
2017-12-11 23:31:23.494688+0800 NSOperation[1569:109434] 我是opB,我后执行 - <NSThread: 0x60000046f2c0>{number = 4, name = (null)}
能够见见,无论运营三次,其结果都以opA先推行,opB后执行。注意:不能够opA注重opB,同期opB重视opA。职务试行的一一,并不取决于增加的各类,推行的各样取决于正视。
7. 其余的方式
// NSOperation提供的方法,可取消单个操作
- (void)cancel;
// NSOperationQueue提供的方法,可以取消队列的所有操作
- (void)cancelAllOperations;
// 可以设置任务的暂停和恢复,YES代表暂停队列,No表示恢复队列。
- (void)setSuspended:(BOOL)b;
// 判断暂停状态
- (BOOL)isSuspended;
// 设置操作优先级 优先级越高,被调用的几率越大
- (NSOperationQueuePriority)queuePriority;
- (void)setQueuePriority:(NSOperationQueuePriority)p;
注意:
–
这里的中断和打消并不表示能够将日前的操作立时打消,而是当当前的操作试行实现后不复推行新的操作。
–
暂停和注销的界别在于:暂停操作之后还能够复苏操作,继续向下实行;而撤回操作之后,全体的操作就清空了,不能够再接着推行剩下的操作。