ios开发中GCD使用很方便,开发中也应用到,NSOperation是对GCD的封装,主流框架多线程大多是使用NSOperation进行多线程开发
- NSOperation对比GCD
- NSOperation基于GCD封装,拥有更多的API
- 在NSOperationQueue中可以指定NSOperation之间的依赖关系
- 可以使用KVO监听状态
- 可定制性,可以继承NSOperation实现可复用的逻辑模块
NSOperation的子类
- NSInnvocationOperation
- NSBlockOperation
- 使用子类NSInvocationOperation
NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test) object:nil];
[operation start];
- (void)test
{
NSLog(@"%@",[NSThread currentThread]);
}
输出结果
2017-11-02 13:11:27.259 TestApp[7602:842337] <NSThread: 0x600000075b80>{number = 1, name = main}
结果看,单独使用NSInvocationOperation 是在主线程上执行的
2.子类NSBlockOperation
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@",[NSThread currentThread]);
}];
[operation start];
输出结果
2017-11-02 13:15:31.283 TestApp[7700:865333] <NSThread: 0x608000260380>{number = 1, name = main}
NSBlockOperation 单独一个执行的时候也是在主线程
为NSBlockOperation添加额外的操作 addExecutionBlock
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@",[NSThread currentThread]);
}];
[operation addExecutionBlock:^{
NSLog(@"2======%@",[NSThread currentThread]);
}];
[operation addExecutionBlock:^{
NSLog(@"3=======%@",[NSThread currentThread]);
}];
[operation start];
输出结果
2017-11-02 13:19:34.229 TestApp[7823:890592] 3=======<NSThread: 0x618000067240>{number = 4, name = (null)}
2017-11-02 13:19:34.228 TestApp[7823:890554] <NSThread: 0x618000065240>{number = 1, name = main}
2017-11-02 13:19:34.229 TestApp[7823:890593] 2======<NSThread: 0x6100000673c0>{number = 3, name = (null)}
可以看到NSBlockOperation在主线程执行,为其添加的操作是在子线程执行的
队列NSOperationQueue
- 主队列
- 其他队列 (串行,并发功能)
- 添加到主队列的任务(nsoperation)都会在主线程执行
NSOperationQueue *mainqueue = [NSOperationQueue mainQueue];
[mainqueue addOperationWithBlock:^{
NSLog(@"1=====%@",[NSThread currentThread]);
}];
[mainqueue addOperationWithBlock:^{
NSLog(@"2=======%@",[NSThread currentThread]);
}];
输出
2017-11-02 13:27:03.589 TestApp[7979:917764] 1=====<NSThread: 0x6180000755c0>{number = 1, name = main}
2017-11-02 13:27:03.590 TestApp[7979:917764] 2=======<NSThread: 0x6180000755c0>{number = 1, name = main}
验证了,任务添加到主队列添加任务都在主队列
其他队列
NSOperationQueue *operationQueue = [[NSOperationQueue alloc]init];
NSInvocationOperation *op1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test) object:nil];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
for (int i = 0; i < 3; i++) {
NSLog(@"1====%@",[NSThread currentThread]);
}
}];
//添加到队列中
[operationQueue addOperation:op1];
[operationQueue addOperation:op2];
}
- (void)test
{
for (int i = 0; i < 3; i++) {
NSLog(@"2====%@",[NSThread currentThread]);
}
}
输出结果
2017-11-02 13:34:26.810 TestApp[8159:944287] 2====<NSThread: 0x610000071740>{number = 3, name = (null)}
2017-11-02 13:34:26.810 TestApp[8159:944307] 1====<NSThread: 0x618000071b80>{number = 4, name = (null)}
2017-11-02 13:34:26.810 TestApp[8159:944287] 2====<NSThread: 0x610000071740>{number = 3, name = (null)}
2017-11-02 13:34:26.810 TestApp[8159:944307] 1====<NSThread: 0x618000071b80>{number = 4, name = (null)}
2017-11-02 13:34:26.812 TestApp[8159:944307] 1====<NSThread: 0x618000071b80>{number = 4, name = (null)}
2017-11-02 13:34:26.812 TestApp[8159:944287] 2====<NSThread: 0x610000071740>{number = 3, name = (null)}
看到 NSInvocationOperation 与NSBlockOperation 和 NSOperationQueue结合能开辟线程,并发执行任务
3.重点是要说控制部分(串行与并行)
NSOperationQueue的串行与并行的控制通过maxConcurrentOperationCount的值大小控制
- 为-1是默认的值表示不限制为并发执行
- 为1时为串行执行
- 大于1时并发执行
```
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//设置最大并发操作数
queue.maxConcurrentOperationCount = 1;
//添加操作
[queue addOperationWithBlock:^{
for (int i = 0; i < 3; i++) {
NSLog(@"1====%@",[NSThread currentThread]);
}
}];
[queue addOperationWithBlock:^{
for (int i = 0; i < 3; i++) {
NSLog(@"2====%@",[NSThread currentThread]);
}
}];
[queue addOperationWithBlock:^{
for (int i = 0; i < 3; i++) {
NSLog(@"3====%@",[NSThread currentThread]);
}
}];
为-1时的结果
2017-11-02 14:03:31.215 TestApp[8789:1047083] 2====<NSThread: 0x610000069d00>{number = 4, name = (null)}
2017-11-02 14:03:31.215 TestApp[8789:1047084] 1====<NSThread: 0x608000065f00>{number = 3, name = (null)}
2017-11-02 14:03:31.215 TestApp[8789:1047086] 3====<NSThread: 0x618000067340>{number = 5, name = (null)}
2017-11-02 14:03:31.215 TestApp[8789:1047083] 2====<NSThread: 0x610000069d00>{number = 4, name = (null)}
2017-11-02 14:03:31.215 TestApp[8789:1047084] 1====<NSThread: 0x608000065f00>{number = 3, name = (null)}
2017-11-02 14:03:31.215 TestApp[8789:1047086] 3====<NSThread: 0x618000067340>{number = 5, name = (null)}
2017-11-02 14:03:31.216 TestApp[8789:1047083] 2====<NSThread: 0x610000069d00>{number = 4, name = (null)}
2017-11-02 14:03:31.216 TestApp[8789:1047084] 1====<NSThread: 0x608000065f00>{number = 3, name = (null)}
2017-11-02 14:03:31.216 TestApp[8789:1047086] 3====<NSThread: 0x618000067340>{number = 5, name = (null)}
可以看出线程为并发执行
为1时的结果
2017-11-02 14:04:55.051 TestApp[8828:1052683] 1====<NSThread: 0x60000006e040>{number = 3, name = (null)}
2017-11-02 14:04:55.051 TestApp[8828:1052683] 1====<NSThread: 0x60000006e040>{number = 3, name = (null)}
2017-11-02 14:04:55.051 TestApp[8828:1052683] 1====<NSThread: 0x60000006e040>{number = 3, name = (null)}
2017-11-02 14:04:55.051 TestApp[8828:1052683] 2====<NSThread: 0x60000006e040>{number = 3, name = (null)}
2017-11-02 14:04:55.052 TestApp[8828:1052683] 2====<NSThread: 0x60000006e040>{number = 3, name = (null)}
2017-11-02 14:04:55.053 TestApp[8828:1052683] 2====<NSThread: 0x60000006e040>{number = 3, name = (null)}
2017-11-02 14:04:55.053 TestApp[8828:1052680] 3====<NSThread: 0x61000006f400>{number = 4, name = (null)}
2017-11-02 14:04:55.053 TestApp[8828:1052680] 3====<NSThread: 0x61000006f400>{number = 4, name = (null)}
2017-11-02 14:04:55.054 TestApp[8828:1052680] 3====<NSThread: 0x61000006f400>{number = 4, name = (null)}
从结果可以看出线程为串行执行
大于1时 取值4
2017-11-02 14:06:49.731 TestApp[8884:1060085] 2====<NSThread: 0x618000065f80>{number = 4, name = (null)}
2017-11-02 14:06:49.731 TestApp[8884:1060115] 1====<NSThread: 0x61000006aa80>{number = 3, name = (null)}
2017-11-02 14:06:49.731 TestApp[8884:1060089] 3====<NSThread: 0x6000000695c0>{number = 5, name = (null)}
2017-11-02 14:06:49.731 TestApp[8884:1060085] 2====<NSThread: 0x618000065f80>{number = 4, name = (null)}
2017-11-02 14:06:49.731 TestApp[8884:1060115] 1====<NSThread: 0x61000006aa80>{number = 3, name = (null)}
2017-11-02 14:06:49.731 TestApp[8884:1060089] 3====<NSThread: 0x6000000695c0>{number = 5, name = (null)}
2017-11-02 14:06:49.732 TestApp[8884:1060085] 2====<NSThread: 0x618000065f80>{number = 4, name = (null)}
2017-11-02 14:06:49.732 TestApp[8884:1060115] 1====<NSThread: 0x61000006aa80>{number = 3, name = (null)}
2017-11-02 14:06:49.732 TestApp[8884:1060089] 3====<NSThread: 0x6000000695c0>{number = 5, name = (null)}
从结果可以看出线程为并行执行
为队列添加依赖(addDependency)
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1====%@",[NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"2====%@",[NSThread currentThread]);
}];
[blockOperation addDependency:op2]; //这里添加依赖,谁在前谁后执行(A依赖B,B先执行 ,B依赖A,A先执行)
[queue addOperation:blockOperation];
[queue addOperation:op2];
输出结果
2017-11-02 14:13:15.036 TestApp[9035:1091092] 2====<NSThread: 0x600000261ac0>{number = 3, name = (null)}
2017-11-02 14:13:15.037 TestApp[9035:1091120] 1====<NSThread: 0x608000260cc0>{number = 4, name = (null)}
NSOperationQueue的实例方法
- cancelAllOperations
- waitUntilAllOperationsAreFinished
首先说(cancelAllOperations)
- -(void)cancelAllOperations; NSOperationQueue提供的方法,可以取消队列的所有操作
waitUntilAllOperationsAreFinished
NSLog(@"执行开始");
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1====%@",[NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
for (int i = 0; i < 5; i++) {
NSLog(@"2====%@",[NSThread currentThread]);
}
}];
[blockOperation addDependency:op2];
[queue addOperation:blockOperation];
[queue addOperation:op2];
[queue waitUntilAllOperationsAreFinished];
NSLog(@"执行到这了");
执行结果
2017-11-02 14:23:53.152 TestApp[9349:1143454] 执行开始
2017-11-02 14:23:53.153 TestApp[9349:1143501] 2====<NSThread: 0x608000071f40>{number = 3, name = (null)}
2017-11-02 14:23:53.153 TestApp[9349:1143501] 2====<NSThread: 0x608000071f40>{number = 3, name = (null)}
2017-11-02 14:23:53.153 TestApp[9349:1143501] 2====<NSThread: 0x608000071f40>{number = 3, name = (null)}
2017-11-02 14:23:53.154 TestApp[9349:1143501] 2====<NSThread: 0x608000071f40>{number = 3, name = (null)}
2017-11-02 14:23:53.154 TestApp[9349:1143501] 2====<NSThread: 0x608000071f40>{number = 3, name = (null)}
2017-11-02 14:23:53.154 TestApp[9349:1143514] 1====<NSThread: 0x61800006f740>{number = 4, name = (null)}
2017-11-02 14:23:53.155 TestApp[9349:1143454] 执行到这了
是上面的队列执行完成以后才会执行下面的内容
再来看一下没有添加 [queue waitUntilAllOperationsAreFinished]; 的执行结果
2017-11-02 14:31:32.247 TestApp[9512:1179286] 执行开始
2017-11-02 14:31:32.247 TestApp[9512:1179286] 执行到这了
2017-11-02 14:31:32.248 TestApp[9512:1179339] 2====<NSThread: 0x610000074dc0>{number = 3, name = (null)}
2017-11-02 14:31:32.248 TestApp[9512:1179339] 2====<NSThread: 0x610000074dc0>{number = 3, name = (null)}
2017-11-02 14:31:32.248 TestApp[9512:1179339] 2====<NSThread: 0x610000074dc0>{number = 3, name = (null)}
2017-11-02 14:31:32.249 TestApp[9512:1179339] 2====<NSThread: 0x610000074dc0>{number = 3, name = (null)}
2017-11-02 14:31:32.249 TestApp[9512:1179339] 2====<NSThread: 0x610000074dc0>{number = 3, name = (null)}
2017-11-02 14:31:32.250 TestApp[9512:1179356] 1====<NSThread: 0x60000006ee00>{number = 4, name = (null)}
说明任务是都添加队列后才执行的