一,什么是NSOpeation
NSOperation是苹果提供给我们的一套多线程解决方案。实际上NSOperation是基于GCD更高一层的封装,但是比GCD更简单易用、代码可读性也更高。
二,NSOperation&NSOperationQueue的基本使用
1,NSOperation
NSOperation是一个抽象类,并不能封装任务,我们只有使用他的子类来封装任务.有三钟方式来封装:
- 使用子类NSInvocationOperation
使用子类NSBlockOperation 定义继承NSOperation的子类,通过实现内部相应的方法来封装任务
NSInvocationOperation
//1,创建NSInvoctionOperation
NSInvocationOperation *invocation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(run) object:nil];
//2,调用start开始操作
[invocation start];
//没有使用NSOperation类时,并没有开启新的线程(在主线程执行)
- NSBlockOperation
//创建NSBlockOperation
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"执行任务-- %@",[NSThread currentThread]);
}];
//start
[blockOperation start];
//使用NSBlockOperation,没有开启行的线程(在主线程执行)
- NSBlockOperation的addExecutionBlock:
//创建NSBlockOperation
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"执行任务1-- %@",[NSThread currentThread]);
}];
// 添加额外的任务(在子线程执行)
[blockOperation addExecutionBlock:^{
NSLog(@"2------%@", [NSThread currentThread]);
}];
[blockOperation addExecutionBlock:^{
NSLog(@"3------%@", [NSThread currentThread]);
}];
[blockOperation addExecutionBlock:^{
NSLog(@"4------%@", [NSThread currentThread]);
}];
[blockOperation start];
//使用NSBlockOperation的addExecutionBlock:方法,会开启线程
- 自定义继承NSOperation的子类
.h文件
import <Foundation/Foundation.h>
@interface GSOperation : NSOperation
@end
.m文件
#import "GSOperation.h"
@implementation GSOperation
//执行需要执行的任务
-(void)main{
for (int i = 0; i < 9; ++i) {
NSLog(@"执行任务--%@",[NSThread currentThread]);
}
}
@end
单独使用自定义子类的情况下,是在主线程执行操作,并没有开启新线程。
2,NSOperationQueue
NSOperationQueue一共有两种队列:主队列、其他队列,其他队列同时包含了串行、并发功能。
主队列:
凡是添加到主队列中的任务(NSOperation),都会放到主线程中执行
NSOperationQueue *queue = [NSOperationQueue mainQueue];其他队列(非主队列)
添加到这种队列中的任务(NSOperation),就会自动放到子线程中执行
同时包含了:串行、并发功能
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
将任务加入到队列中
总共有两种方法:
1,NSOperationQueue的addOperation:方法,需要先创建任务,再将创建好的任务加入到创建好的队列中去
// 1.创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 2. 创建操作
// 创建NSInvocationOperation
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
// 创建NSBlockOperation
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
for (int i = 0; i < 2; ++i) {
NSLog(@"1-----%@", [NSThread currentThread]);
}
}];
// 3. 添加操作到队列中:addOperation:
[queue addOperation:op1]; // [op1 start]
[queue addOperation:op2]; // [op2 start]
总结:不管是NSInvocationOperation,还是NSBlockOperation,在添加到队列后都可以并发执行,
2,addOperationWithBlock:无需先创建任务,在block中添加任务,直接将任务block加入到队列中.
// 1. 创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 2. 添加操作到队列中:addOperationWithBlock:
[queue addOperationWithBlock:^{
for (int i = 0; i < 2; ++i) {
NSLog(@"-----%@", [NSThread currentThread]);
}
}];
总结:可以并行执行
三,控制串行执行和并行执行的关键
NSOperationQueue创建的其他队列同时具有串行、并发功能,关键操作在于maxConcurrentOperationCount:(最大并发数)这个参数中
- 默认情况下maxConcurrentOperationCount为-1,表示不进行限制,默认为并发执行。
- 当maxConcurrentOperationCount为1时,进行串行执行。
- 当maxConcurrentOperationCount大于1时,进行并发执行,当然这个值不应超过系统限制,即使自己设置一个很大的值,系统也会自动调整。
// 创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 设置最大并发操作数
// queue.maxConcurrentOperationCount = 2;
queue.maxConcurrentOperationCount = 1; // 就变成了串行队列
// 添加操作
[queue addOperationWithBlock:^{
NSLog(@"1-----%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:0.01];
}];
[queue addOperationWithBlock:^{
NSLog(@"2-----%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:0.01];
}];
[queue addOperationWithBlock:^{
NSLog(@"3-----%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:0.01];
}];
[queue addOperationWithBlock:^{
NSLog(@"4-----%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:0.01];
}];
[queue addOperationWithBlock:^{
NSLog(@"5-----%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:0.01];
}];
[queue addOperationWithBlock:^{
NSLog(@"6-----%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:0.01];
}];
总结:当最大并发数为1时,任务是按顺序串行执行的。当最大并发数为2时,任务是并发执行的。而且开启线程数量是由系统决定的,不需要我们来管理。
四,操作依赖
A、B两个操作,其中A执行完操作,B才能执行操作,那么就需要让B依赖于A。具体如下:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1-----%@", [NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"2-----%@", [NSThread currentThread]);
}];
[op2 addDependency:op1]; // 让op2 依赖于 op1,则先执行op1,在执行op2
[queue addOperation:op1];
[queue addOperation:op2];
执行结果是:op1先执行,op2后执行;
以上是学习后的一些总结,有什么错误的还请各位指点