任务配合队列使用 NSOperation、NSOperationQueue?使用的原因
1.可添加完成的代码块,在操作完成后执行。
2.添加操作之间的依赖关系,方便的控制执行顺序。
3.设定操作执行的优先级。
4.可以很方便的取消一个操作的执行。
5.使用 KVO 观察对操作执行状态的更改:isExecuteing、isFinished、isCancelled6.可以控制线程的数量 通过设置属性maxConcurrentOperationCount [SD 默认是6]
一.创建普通任务
1.系统提供 NSInvocationOperation
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
NSInvocationOperation *invocation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downLoadImage) object:@""];
NSInvocationOperation *invocation1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downLoadImage) object:@""];
NSInvocationOperation *invocation2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downLoadImage) object:@""];
[queue addOperation:invocation];//等于调用start方法
[queue addOperation:invocation1];//等于调用start方法
[queue addOperation:invocation2];//等于调用start方法
2.系统提供 NSBlockOperation
//1.创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//2.封装操作
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1----%@",[NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"2----%@",[NSThread currentThread]);
}];
[op2 addExecutionBlock:^{
NSLog(@"3----%@",[NSThread currentThread]);
}];
[op2 addExecutionBlock:^{
NSLog(@"4----%@",[NSThread currentThread]);
}];
//3.添加操作到队列中
[queue addOperation:op1];
[queue addOperation:op2];
3.系统提供 addOperationWithBlock
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
[queue addOperationWithBlock:^{
NSLog(@"1----%@",[NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"2----%@",[NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"3----%@",[NSThread currentThread]);
}];
4.自定义继承与NSOperation的任务
通过重写 main 或者 start 方法 来定义自己的 NSOperation 对象。重写main方法比较简单,我们不需要管理操作的状态属性 isExecuting 和 isFinished。当 main 执行完返回的时候,这个操作就结束
#import "WJOperation.h"
@implementation WJOperation
- (void)main
{
//耗时操作1
for (int i = 0; i<1000; i++) {
NSLog(@"任务1-%d--%@",i,[NSThread currentThread]);
}
NSLog(@"+++++++++++++++++++++++++++++++++");
//苹果官方建议,每当执行完一次耗时操作之后,就查看一下当前队列是否为取消状态,如果是,那么就直接退出
//好处是可以提高程序的性能
if (self.isCancelled) {
return;
}
//耗时操作2
for (int i = 0; i<1000; i++) {
NSLog(@"任务2-%d--%@",i,[NSThread currentThread]);
}
NSLog(@"+++++++++++++++++++++++++++++++++");
}
@end
二.创建相互依赖任务[图片拼接]
- (void)download2
{
NSLog(@"----");
//1.创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//2.封装操作下载图片1
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSURL *url = [NSURL URLWithString:@"http://h.hiphotos.baidu.com/zhidao/pic/item/6a63f6246b600c3320b14bb3184c510fd8f9a185.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
//拿到图片数据
self.image1 = [UIImage imageWithData:data];
}];
//3.封装操作下载图片2
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSURL *url = [NSURL URLWithString:@"http://pic.58pic.com/58pic/13/87/82/27Q58PICYje_1024.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
//拿到图片数据
self.image2 = [UIImage imageWithData:data];
}];
//4.合成图片
NSBlockOperation *combine = [NSBlockOperation blockOperationWithBlock:^{
//4.1 开启图形上下文
UIGraphicsBeginImageContext(CGSizeMake(200, 200));
//4.2 画image1
[self.image1 drawInRect:CGRectMake(0, 0, 200, 100)];
//4.3 画image2
[self.image2 drawInRect:CGRectMake(0, 100, 200, 100)];
//4.4 根据图形上下文拿到图片数据
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
//4.5 关闭图形上下文
UIGraphicsEndImageContext();
//7.回到主线程刷新UI
[[NSOperationQueue mainQueue]addOperationWithBlock:^{
self.imageView.image = image;
NSLog(@"刷新UI---%@",[NSThread currentThread]);
}];
}];
//5.设置操作依赖
[combine addDependency:op1];
[combine addDependency:op2];
//6.添加操作到队列中执行
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:combine];
}
三.NSOperation 属性
@property (readonly, getter=isCancelled) BOOL cancelled;//操作是否取消
@property (readonly, getter=isExecuting) BOOL executing;//是否执行
@property (readonly, getter=isFinished) BOOL finished;//是否执行结束
@property (readonly, getter=isAsynchronous) BOOL asynchronous //是否异步
@property (readonly, getter=isReady) BOOL ready;//是否处于就绪状态
@property (readonly, copy) NSArray<NSOperation *> *dependencies;//所有相关依赖
- (void)cancel;//取消操作
- (void)waitUntilFinished;//执行该操作的时候阻塞当前线程,直到该操作执行
- (void)addDependency:(NSOperation *)op;//添加依赖
- (void)removeDependency:(NSOperation *)op;//去除依赖
四. NSOperationQueue的相关属性和方法
@property (readonly, copy) NSArray<__kindof NSOperation *> *operations;
@property (readonly) NSUInteger operationCount ;//操作的个数
@property NSInteger maxConcurrentOperationCount;//最大并发数
@property (getter=isSuspended) BOOL suspended;//是否悬挂
@property (nullable, assign actually retain ) dispatch_queue_t underlyingQueue;//操作队列对应的GCD队列。
- (void)cancelAllOperations;//取消队列中的所有操作。
添加队列
- (void)addOperation:(NSOperation *)op;
- (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait ;//可以根据wait参数设置队列中操作的执行方式是串行还是并发。
- (void)addOperationWithBlock:(void (^)(void))block;
面试问题:
1.NSOperation有哪些状态:ready executing finished cancelled
2.NSOperation状态控制?
(1)如果使用的是NSInvocationOperation NSBlockOperation 状态由系统控制
(2)如果重写了NSOperation
1.如果重写了main方法 状态由系统控制
2.如果重写了start方法 由我们自己控制
3.系统是如何移除一个isFinish为yes的NSOperation?
看源码是通过KVO
网友评论