简介
- 概念
核心概念:将“操作”添加到“队列”
- 特点
不能直接使用!!! 目的是定义子类共有的属性和方法
- 子类
NSInvocationOperation
NSBlockOperation
与GCD不同
GCD :将“任务”添加“队列”
调用方法
通过两个子类调用NSInvocationOperation和NSBlockOperation
NSInvocationOperation
//操作
NSInvocationOperation *op = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downImage:) object:@"invocation"];
//会在当前的线程执行调度方法
// [op start];
//队列
NSOperationQueue *q = [[NSOperationQueue alloc]init];
//将操作添加到队列--会自动异步执行调度方法
[q addOperation:op];
循环添加10个个
//1.队列
NSOperationQueue *q = [[NSOperationQueue alloc]init];
for (int i = 0; i < 10 ; i++) {
NSInvocationOperation *op = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downImage:) object:@(i)];
//添加到队列
[q addOperation:op];
}
执行结果
NSBlockOperation
//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];
还有一种更简便的方法
//1.队列
NSOperationQueue *q = [[NSOperationQueue alloc]init];
//2.操作
for (int i = 0; i < 10;i++) {
[q addOperationWithBlock:^{
NSLog(@"%@----%d",[NSThread currentThread],i);
}];
}
多线程直接通信
[self.opQueue addOperationWithBlock:^{
NSLog(@"——————%@",[NSThread currentThread]);
//主线程
[[NSOperationQueue mainQueue]addOperationWithBlock:^{
NSLog(@"MainThread %@",[NSThread currentThread]);
}];
}];
线程依赖
当某个NSOperation对象依赖于其它NSOperation对象的完成时,就可以通过addDependency方法添加一个或者多个依赖的对象,只有所有依赖的对象都已经完成操作,当前NSOperation对象才会开始执行操作。另外,通过removeDependency方法来删除依赖对象。
[operation2 addDependency:operation1];
依赖关系不局限于相同queue中的NSOperation对象,NSOperation对象会管理自己的依赖, 因此完全可以在不同的queue之间的NSOperation对象创建依赖关系
唯一的限制是不能创建环形依赖,比如A依赖B,B依赖A,这是错误的
例子
- 没有设置依赖关系
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"执行第1次操作,线程:%@", [NSThread currentThread]);
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"执行第2次操作,线程:%@", [NSThread currentThread]);
}];
[queue addOperation:operation1];
[queue addOperation:operation2];
结果为
2017-09-06 14:10:03.561 006--NSOperation[24172:1622100] 执行第2次操作,线程:<NSThread: 0x608000266880>{number = 4, name = (null)}
2017-09-06 14:10:03.561 006--NSOperation[24172:1622099] 执行第1次操作,线程:<NSThread: 0x600000270d80>{number = 3, name = (null)}
可以看到1和2直接顺序不固定
- 设置依赖关系
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"执行第1次操作,线程:%@", [NSThread currentThread]);
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"执行第2次操作,线程:%@", [NSThread currentThread]);
sleep(2);
}];
// operation1依赖于operation2
[operation1 addDependency:operation2];
[queue addOperation:operation1];
[queue addOperation:operation2];
结果
2017-09-06 14:12:19.662 006--NSOperation[24236:1626990] 执行第2次操作,线程:<NSThread: 0x600000072b40>{number = 3, name = (null)}
//两秒后执行下面
2017-09-06 14:12:21.737 006--NSOperation[24236:1626994] 执行第1次操作,线程:<NSThread: 0x608000070840>{number = 4, name = (null)}
可以看到再2执行之后才执行1
最大并发数
从iOS 8.0 开始,无论是GCD 还是NSOperation 都会开启很多线程
在 iOS 7.0以前GCD ,一般开5-6;
目前线程多说明:
1. 底层的线程池更大了,能够拿到更多的线程资源了
2. 多线程同时并发的现场数,要求更高了。
//设置同时最大的并发操作熟练
self.opQueue.maxConcurrentOperationCount = 2;
/*
20文件?20线程?
//WiFi :5-6;
//流量: 2-3
*/
for (int i = 0; i < 20; i++) {
[self.opQueue addOperationWithBlock:^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"%@------%d",[NSThread currentThread],i);
}];
}
总结
苹果大力推进iOS开发者使用!
NSOperation 和 GCD对比
- GCD 在iOS 4.0 推出,主要多核处理器优化的并发技术,是C语言的
- 将任务(block)添加到队列(串行、并行、主队列、全局队列),并且要指定任务的同步、异步;
- 线程间的通讯 dispatch_get_main_queue()
- 提供了一些 NSOperation不具备的功能:
- 一次执行(单例)
- 延迟执行
- 调度组(NSOperation 也可以做到,但是有点麻烦)
- NSOperation 在iOS 2.0;苹果推出了GCD之后,对NSOperation 进行了重写
- 将操作[异步执行的任务]添加到 【并发队列】,就会立刻异步执行
- 提供了一个些GCD实现起来比较麻烦功能
- 最大并发线程
- 队列的暂停、继续
- 取消所有线程
- 线程依赖(线程A 的执行必须 依赖线程B)(GCD 同步实现!)