NSOperation的介绍
-
NSOperation是基于GCD的封装,它的底层其实就是GCD
-
核心概念
- 队列 + 操作
-
为什么要封装这个类呢?
-
因为这个是OC的,更加面向对象,可以直接调用属性和方法
-
NSOperation的作用
- 配合使用NSOperation和NSOperationQueue也能实现多线程编程
-
NSOperation和NSOperationQueue实现多线程的具体步骤
-
先将需要执行的操作封装到一个NSOperation对象中
-
然后将NSOperation对象添加到NSOperationQueue中
-
系统会自动将NSOperationQueue中的NSOperation取出来
-
将取出的NSOperation封装的操作放到一条新线程中执行
-
NSOperation的基本使用
- NSOperation本身是抽象类,只能只有它的子类
- 三个子类分别是:NSBlockOperation、NSInvocationOperation以及自定义继承自NSOperation的类
- NSOperation和NSOperationQueue结合使用实现多线程并发
-
NSInvocationOperation
//1.封装操作
第一个参数:目标对象
第二个参数:该操作要调用的方法,最多接受一个参数
第三个参数:调用方法传递的参数,如果方法不接受参数,那么该值传nil
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self selector:@selector(sel) object:nil];
//2.启动操作
[operation start];
#注意: 调用start不会开启新的线程执行,而是在当前线程中执行任务
# 只有将 NSOperation放到一个NSOperationQueue中,才会异步执行操作
- NSBlockOperation
//1.封装操作
NSBlockOperation提供了一个类方法,在该类方法中封装操作
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
//在主线程中执行
NSLog(@"---download1--%@",[NSThread currentThread]);
}];
//2.追加操作,追加的操作在子线程中执行
[operation addExecutionBlock:^{
NSLog(@"---download2--%@",[NSThread currentThread]);
}];
[operation addExecutionBlock:^{
NSLog(@"---download3--%@",[NSThread currentThread]);
}];
//3.启动执行操作
[operation start];
#注意:只要NSBlockOperation封装的操作数 > 1,就会异步执行操作(默认就是并发队列)
基本步骤:
1.封装操作
2.创建队列 (默认是并发队列)
3,将操作添加到队列中
- 简便的方法
//创建队列
NSOperationQueue *queue
//提交操作到队列中
[queue addOperationWithBlock:^{ 操作 }]
- 自定义NSOperation的好处
有利于代码复用;
有利于代码隐藏;
具体的实现代码在继承NSOperation中的类里面的main方法里面实现;
- NSOperation的两种队列
- 主队列 通过mainQueue获得,凡是放到主队列中的任务都将在主线程执行
- 非主队列 直接alloc init出来的队列。非主队列同时具备了并发和串行的功能,通过设置最大并发数属性来控制任务是并发执行还是串行执行
- 设置最大并发数
//1.创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//2.设置最大并发数
//注意点:该属性需要在任务添加到队列中之前进行设置
//该属性控制队列是串行执行还是并发执行
//如果最大并发数等于1,那么该队列是串行的,如果大于1那么是并行的
//系统的最大并发数有个默认的值,为-1,如果该属性设置为0,那么不会执行任何任务
queue.maxConcurrentOperationCount = 2;
- 暂停 恢复 以及 取消
//设置暂停和恢复
//suspended设置为YES表示暂停,suspended设置为NO表示恢复
//暂停表示不继续执行队列中的下一个任务,暂停操作是可以恢复的
if (self.queue.isSuspended) {
self.queue.suspended = NO;
}else {
self.queue.suspended = YES;
}
//取消队列里面的所有操作
//取消之后,当前正在执行的操作的下一个操作将不再执行,而且永远都不在执行,就像后面的所有任务都从队列里面移除了一样
//取消操作是不可以恢复的
[self.queue cancelAllOperations];
- 操作依赖
- NSOperation之间可以通过设置依赖保证执行顺序
- 如:执行完操作A之后才能执行操作B
[operationA addDependency :operationB];
注意:不能互相依赖,如:操作A依赖操作B 操作B依赖操作A
NSOperation实现线程之间的通信
//1.创建队列
NSOperationQueue *queue =[[NSOperationQueue alloc]init];
//2.封装操作
NSBlockOperation *download1 = [NSBlockOperation blockOperationWithBlock:^{
//2.1 请求url
NSURL *url = [NSURL URLWithString:@"http://img.qiyenet.net/upload/image/2016/03/05/1457133748832510.png"];
//2.2 下载图片的二进制数据
NSData *data = [NSData dataWithContentsOfURL:url];
//2.3 转换图片
self.image1 = [UIImage imageWithData:data];
}];
//3.下载图片2
NSBlockOperation *download2 = [NSBlockOperation blockOperationWithBlock:^{
//3.1 请求url
NSURL *url = [NSURL URLWithString:@"http://www.52tq.net/uploads/allimg/160226/1021043B3-3.jpg"];
//3.2 下载图片的二进制数据
NSData *data = [NSData dataWithContentsOfURL:url];
//3.3转换图片
self.image2 = [UIImage imageWithData:data];
}];
//4.合并图片
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
UIGraphicsBeginImageContext(CGSizeMake(200, 200));
[self.image1 drawInRect:CGRectMake(0, 0, 100, 200)];
[self.image2 drawInRect:CGRectMake(100, 0, 100, 200)];
self.image1 = nil;
self.image2 = nil;
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//线程间通信
[[NSOperationQueue mainQueue]addOperationWithBlock:^{
self.imageView.image = image;
}];
}];
[op addObserver:self forKeyPath:@"isFinished" options:NSKeyValueObservingOptionNew context:nil];
//5.设置依赖关系
[op addDependency:download1];
[op addDependency:download2];
//6.添加操作到队列
[queue addOperation:op];
[queue addOperation:download1];
[queue addOperation:download2];
网友评论
运行最后一段代码报这个错误,还要添加些什么?
这个结论是如何得出的?