iOS NSOperation

2018-07-25  本文已影响12人  Rumbles

任务配合队列使用 NSOperation、NSOperationQueue?使用的原因

1.可添加完成的代码块,在操作完成后执行。
2.添加操作之间的依赖关系,方便的控制执行顺序。
3.设定操作执行的优先级。
4.可以很方便的取消一个操作的执行。
5.使用 KVO 观察对操作执行状态的更改:isExecuteing、isFinished、isCancelled

6.可以控制线程的数量 通过设置属性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

上一篇下一篇

猜你喜欢

热点阅读