NSOperation在ios2出来的,后来又基于GCD进行了重写,但是相对于GCD来说可控性更强,并且可以加入操作依赖。
NSOperation是一个抽象的基类,表示一个独立的计算单元,可以为子类提供有用且线程安全的建立状态,优先级,依赖和取消等操作。系统已经给我们封装了NSBlockOperation和NSInvocationOperation这两个实体类。使用起来也非常简单,不过我们更多的使用是自己继承并定制自己的操作。
NSOperation 和 GCD对比:
(1) GCD ,主要多核处理器优化的并发技术,是C语言的
将任务(block)添加到队列(串行、并行、主队列、全局队列),并且要指定任务的同步、异步;
线程间的通讯 dispatch_get_main_queue()
提供了一些 NSOperation不具备的功能:
一次执行(单例)
延迟执行
调度组(NSOperation 也可以做到,但是有点麻烦)
(2)NSOperation 在iOS 2.0;苹果推出了GCD之后,对NSOperation 进行了重写
将操作[异步执行的任务]添加到 【并发队列】,就会立刻异步执行,NSOperation需要配合NSOperationQueue使用
提供了一个些GCD实现起来比较麻烦功能
最大并发线程
队列的暂停、继续
取消所有线程
线程依赖(线程A 的执行必须 依赖线程B)(GCD 同步实现!)
一. 首先对NSOperationQueue说明
NSOperationQueue相当于GCD中的队列(dispatch_queue_t)。和GCD中的并发队列、串行队列略有不同的是:NSOperationQueue一共有两种队列:主队列、其他队列。其中其他队列同时包含了串行、并发功能。下边是主队列、其他队列的基本创建方法和特点。
主队列: 凡是添加到主队列中的任务(NSOperation),都会放到主线程中执行;
通过 NSOperationQueue *queue = [NSOperationQueue mainQueue] 获取;
其他队列(同时包含了:并发功能,非主队列):添加到这种队列中的任务(NSOperation),就会自动放到子线程中执行
通过NSOperationQueue *queue = [[NSOperationQueue alloc] init]获取;
那么对于其他队列如何像GCD一样控制串行执行和并行执行呢?
这里有个关键参数maxConcurrentOperationCount,叫做最大并发数。
maxConcurrentOperationCount默认情况下为-1,表示不进行限制,默认为并发执行。
当maxConcurrentOperationCount为1时,可以当作是串行队列,但是本质上其实还是并发队列,只是被限制了一次只能执行一个任务。
当maxConcurrentOperationCount大于1时,进行并发执行,当然这个值不应超过系统限制,即使自己设置一个很大的值,系统也会自动调整。
二. 两个系统提供的子类使用介绍 NSInvocationOperation ,NSBlockOperation
1.NSInvocationOperation使用(2.0就有了)
-(void)demo{
//1.队列
NSOperationQueue *q = [[NSOperationQueue alloc]init];
q.maxConcurrentOperationCount = 1;
for (int i = 0; i < 10 ; i++) {
//创建操作任务
NSInvocationOperation *op = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downImage:) object:@(i)];
//添加到队列
[q addOperation:op];
}
}
-(void)downImage:(id)objc{
NSLog(@"%@ %@",[NSThread currentThread],objc);
}
输出结果:
![](https://img.haomeiwen.com/i6169007/f032653cee1b3766.png)
分析:由于操作任务加入到其他队列中,该队列默认并发数为1,所以相当于串行队列,所以该队列中的任务会串行执行。但是为何不在同一个线程中执行?(疑问)。这里设置为1,效果只是相当于串行队列一样串行执行,但是NSOperationQueue *q = [[NSOperationQueue alloc]init]本质上是异步并发队列,所以还是会开启多条线程,只是同一时间只能使用其中一条来执行任务而已。
2.NSBlockOperation使用(4.0才有)
-(void)demo{
//1.队列
NSOperationQueue *q = [[NSOperationQueue alloc]init];
//2.操作
for (int i = 0; i < 10;i++) {
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@----%d",[NSThread currentThread],i);
}];
//操作添加到队列
[q addOperation:op];
}
}
输出结果:
![](https://img.haomeiwen.com/i6169007/679684ec448153bf.png)
分析:由于操作任务加入到其他队列中,该队列默认并发数为默认值,所以为并发队列,所以该队列中的任务会并行执行
3.不使用NSOperation子类,直接使用NSOperationQueue添加任务
-(void)demo{
//1.队列
NSOperationQueue *q = [[NSOperationQueue alloc]init];
//2.操作任务直接以block的形式添加到队列中
for (int i = 0; i < 10;i++) {
[q addOperationWithBlock:^{
NSLog(@"%@----%d",[NSThread currentThread],i);
}];
}
}
输出结果:
![](https://img.haomeiwen.com/i6169007/ea69fd4e2a5827d0.png)
4.线程间通信
-(void)demo6{
NSOperationQueue *q = [[NSOperationQueue alloc]init];
[q addOperationWithBlock:^{
NSLog(@"——————%@",[NSThread currentThread]);
//主线程
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"MainThread %@",[NSThread currentThread]);
}];
}];
}
输入结果:
![](https://img.haomeiwen.com/i6169007/a0681191edadc026.png)
网友评论