美文网首页ios常用功能
iOS多线程之NSOperation

iOS多线程之NSOperation

作者: 流云_henry | 来源:发表于2020-07-10 18:24 被阅读0次

    可以将NSOperation理解为任务操作,将NSOperationQueue理解为操作队列。
    NSOperation是基于Objective-C封装的一套管理与执行线程操作的类。这个类是一个抽象类,通常情况下,我们会使用NSInvocationOperation和NSBlockOperation这两个子类来进行多线程开发,当然我们也可以写继承于NSOperation的类,封装我们自己的操作类。

    1、关于NSOperation基类的解析

    NSOperation类是NSInvocationOperation和NSBlockOperation类的父类,其中封装了基础的任务操作行为。其主要属性如下:

    /*激活操作任务*/
    - (void)start;
    
    /*取消任务的执行*/
    - (void)cancel;
    
    /*这个方法留给子类重写,子类可以在这个方法中实现具体的操作执行行为*/
    - (void)main;
    
    /*阻塞当前现在,直到操作完成*/
    - (void)waitUntilFinished;
    
    //一些常用属性
    /*当前操作是否取消 */
    @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 NSOperationQueuePriority queuePriority;
    /* 设置操作执行完成后的回调*/
    @property (nullable, copy) void (^completionBlock)(void);
    /* 设置线程的优先级*/
    @property double threadPriority;
    /* 设置当前操作的名称*/
    @property (nullable, copy) NSString *name;
    

    2、NSBlockOperation类的应用

    NSBlockOperation是NSOperation的一个子类,其可以异步执行多个Block代码块,当所有的Block都执行完成时,这个操作才算完成。
    其常见方法属性如下:

    /*初始化 */
    + (instancetype)blockOperationWithBlock:(void (^)(void))block;
    
    /* 当对象初始化完成后,可以使用下面的方法来追加任务Block*/
    - (void)addExecutionBlock:(void (^)(void))block;
    
    /* 通过下面的属性可以获取NSBlockOperation对象中所追加的所有任务Block*/
    @property (readonly, copy) NSArray<void (^)(void)> *executionBlocks;
    

    关于其应用,示例如下:

        NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
            for (int i = 0; i < 5; i ++) {
                NSLog(@"%@ = %d",[NSThread currentThread],i);
            }
        }];
        [operation addExecutionBlock:^{
            for (int i = 0; i < 5; i ++) {
                NSLog(@"%@ = %d",[NSThread currentThread],i);
            }
        }];
        [operation start];
    

    打印信息:


    image.png

    从打印信息可以看出,两个for循环是在不同的线程中执行的,并且是异步执行。使用NSBlockOperation的一大好处是开发者不需要显示的操作NSThred来管理线程,NSBlockOperation会自动更具加入其中的任务Block来分配线程,使之异步执行。

    3、NSInvocationOperation类的应用

    NSInvocationOperation也是NSOperation的一个子类,和NSBlockOperation不同的是,这个类所执行的操作是在当前线程中同步执行的。其初始化方法如下:

    /* 通过选择器来初始化对象*/
    - (nullable instancetype)initWithTarget:(id)target selector:(SEL)sel object:(nullable id)arg;
    
    /*通过NSInvocation来初始化对象 */
    - (instancetype)initWithInvocation:(NSInvocation *)inv;
    

    应用的示例代码:

    - (void)creatInvocationOperation {
        NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(log) object:nil];
        [operation start];
        for (int i = 0; i < 5; i ++) {
            NSLog(@"1-%@ = %d",[NSThread currentThread],i);
        }
    }
    
    - (void)log {
        for (int i = 0; i < 5; i ++) {
            NSLog(@"2-%@ = %d",[NSThread currentThread],i);
        }
    }
    

    打印信息如下:


    image.png

    从打印信息可以看出,NSInvocationOperation中的任务也是在主线程中执行的。

    4、操作之间的依赖关系

    操作之间常存在一些依赖关系。例如我们在开发应用时,经常会使用网络请求的数据渲染界面。其实请求操作与界面渲染操作就存在依赖关系,界面的渲染一定要依赖数据请求完成。依赖关系和优先级的作用很像,也有所不同。如果一个操作A依赖于另一个操作B,那么只有当B操作完成后,A操作才能执行。

    /*操作添加依赖 */
    - (void)addDependency:(NSOperation *)op;
    
    /*删除一个依赖*/
    - (void)removeDependency:(NSOperation *)op;
    

    从原则上说,一个操作对象可以添加多个依赖,并且当所有依赖都执行完成后才会执行这个操作。

    5、NSOperationQueue操作队列的应用

    NSOperationQueue是操作队列类,通过上面的介绍,我们已经可以理解操作对象,并且操作对象默认的执行方式是串行的。如果将操作对象放入操作队列中,则默认为并行执行的。
    示例代码如下:

    - (void)creatOperationQueue {
        NSOperationQueue *queue = [[NSOperationQueue alloc]init];
        NSInvocationOperation *operation1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(log) object:nil];
        [queue addOperation:operation1];
        for (int i = 0; i < 5; i ++) {
            NSLog(@"1-%@ = %d",[NSThread currentThread],i);
        }
    }
    
    - (void)log {
        for (int i = 0; i < 5; i ++) {
            NSLog(@"2-%@ = %d",[NSThread currentThread],i);
        }
    }
    

    打印信息:


    image.png

    从打印数据可以看出,队列的操作是在一个新的线程中执行的,并且操作队列之中的操作也都是在异步执行的。
    NSOperationQuere类中相关的方法和属性如下:

    /* 在队列中添加一个操作任务*/
    - (void)addOperation:(NSOperation *)op;
    
    /*在队里中插入一组操作任务,后面的参数设置是否在队列中的任务都执行完成后,再执行这一组操作 */
    - (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait ;
    
    /*在队列中添加一个block操作 */
    - (void)addOperationWithBlock:(void (^)(void))block;
    
    /*设置队列的最大并行操作数量 */
    @property NSInteger maxConcurrentOperationCount;
    /* 设置是否暂停队列任务执行*/
    @property (getter=isSuspended) BOOL suspended;
    /* 设置队列名*/
    @property (nullable, copy) NSString *name ;
    /*设置队列的优先级 */
    @property NSQualityOfService qualityOfService;
    
    /* 取消队列中的所有操作任务*/
    - (void)cancelAllOperations;
    /* 阻塞当前线程,知道队列中所有任务完成*/
    - (void)waitUntilAllOperationsAreFinished;
    /* 获取当前线程*/
    @property (class, readonly, strong, nullable) NSOperationQueue *currentQueue;
    /* 获取主线程中的操作队列*/
    @property (class, readonly, strong) NSOperationQueue *mainQueue;
    

    关于操作队列中操作的执行顺序,只要牢记下面的法则即可:
    ·决定于依赖关系,只有当这个操作的依赖全部执行完成后,它才会被执行。
    ·影响于优先级,优先级高的会先执行。
    示例如下:

    - (void)creatOperationDependency {
        //创建队列
        NSOperationQueue *queue = [[NSOperationQueue alloc]init];
        //创建操作任务
        NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
            for (int i = 0; i < 5; i ++) {
                NSLog(@"%@-%d:1",[NSThread currentThread],i);
                sleep(0.5);
            }
        }];
        
        NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
            for (int i = 0; i < 5; i ++) {
                NSLog(@"%@-%d:2",[NSThread currentThread],i);
                sleep(0.5);
            }
        }];
        
        //添加依赖
        [operation2 addDependency:operation1];
        [queue addOperation:operation1];
        [queue addOperation:operation2];
    }
    
    

    打印信息:


    image.png

    从打印信息我们可以看出,本来是两个并发异步的任务,在增加依赖关系后,只有当被依赖的任务全部完成后,才执行当前任务。

    相关文章

      网友评论

        本文标题:iOS多线程之NSOperation

        本文链接:https://www.haomeiwen.com/subject/wnumcktx.html