iOS-多线程编程学习之NSOperation(四)

  NSOperation是一个抽象类,可以用来封装一个任务的相关代码和数据。因为这是个抽象类,所以不能直接得到该类的实例化对象,而是需要继承该类实现其子类或者使用系统内置的两个子类(NSInvocationOperationNSBlockOperation)来执行实际的线程任务。

  一个Operation对象包含的任务只能执行一次。通常情况下只需要把Operation对象加入Operation queue(它是NSOperationQueue类的一个实例)即可。一个Operation queue可以直接执行Operation,或者开第二个线程运行Operation,甚至是间接的使用libdispatch库(类似GCD)。
  如果不使用Operation queue,也可以通过调用其start方法执行一个Operation。手动启动Operation会相对困难一点,因为一不小心启动一个不处于准备状态(ready trigger)的Operation将会导致异常发生。
  在这里我们不打算对NSOperation进行过多的说明。我们主要集中于介绍如何使用系统提供的NSInvocationOperationNSBlockOperationNSOperationQueue来进行多线程编程。

一、简单入门

使用Operation进行多线程编程的步骤很简单。

  • 实例化NSOperation子类实例,绑定要执行的操作。
  • 创建NSOperationQueue队列,并将NSOperation实例添加到队列中。

  然后NSOperationQueue队列将会自动检测队列中需要执行的Operation对象并执行它们。所有使用非常简单,还不需要对Operation的生命周期进行维护。

  在样例代码中首先创建了一个NSOperationQueue类型的属性,并且重写init方法对齐进行初始化操作。部分代码如下

    @property (nonatomic, strong) NSOperationQueue *queue;

    //重写init方法初始化该属性
    -(instancetype)init
    {
        self = [super init];
        if (self) {
            _queue = [[NSOperationQueue alloc] init];
        }
        return self;
    }

1.1 NSInvocationOperation

  创建NSInvocationOperation主要有两个方法。

方法一

    //方法一,创建执行特定方法的Operation
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(selector) object:nil];
    [self.queue addOperation:operation];

方法二

  对于NSInvocation,本质上是OC消息的一种静态描述,可以将其看成是把一个动作(action)封装到一个对象中。一个NSInvocation对象包含了OC消息的所有元素:目标(target),选择器(selector),参数(arguement),返回值(return value)。每个元素都是可以设置的,并且返回值会在齐被调度后自动设置相应的值。

    //方法二,创建NSInvocation对象,并设置其相应参数,在用于创建NSInvocationOperation实例
    NSInvocation *invocation =
        [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:@selector(run)]];
    //设置selector属性
    [invocation setSelector:@selector(run)];
    //设置target属性
    [invocation setTarget:self];
    //创建实例
    NSInvocationOperation *operation2 = [[NSInvocationOperation alloc] initWithInvocation:invocation];
    [self.queue addOperation:operation2];

1.2 NSBlockOperation

NSBlockOperation是NSOperation的一个子类之一。其创建方式比NSInvocationOperation看起来要更简便一点。

    //创建实例
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        for (int i = 0; i < 100; i++) {
            NSLog(@"%zd ===> %@", i, [NSThread currentThread]);
        }
    }];
    //添加到队列中
    [self.queue addOperation:operation];

二、自定义NSOperation子类

  自定义NSOperation子类和自定义NSThread子类的方式非常的像,都是继承父类,重写它们的main方法执行特定的任务。

LYSOperation.h

    #import <Foundation/Foundation.h>

    @interface LYSOperation : NSOperation
    @end

LYSOperation.m

    /**
     *  重写main方法,里面是Operation被调度时执行的任务
     */
    -(void)main
    {
        NSLog(@"这里是自定义的NSOperation子类LYSOperation的实现.");
    }

然后我们想使用别的NSOperation子类一样,只要将其加入NSOperationQueue队列中即可。

    LYSOperation *operation = [[LYSOperation alloc] init];
    [self.queue addOperation:operation];

三、Operation间依赖关系

  NSOperation还有一个特性就是可以创建Operation之间的依赖关系。就是如果A依赖于B,则A需要在B执行完之后才会执行。这样我们就可以很方便拥有特定执行顺序的任务集了。但是需要注意的是要避免创建依赖循环!

    NSBlockOperation *operationA = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"以来测试 ===> 任务A");
    }];

    NSBlockOperation *operationB = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"以来测试 ===> 任务B");
    }];

    NSBlockOperation *operationC = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"以来测试 ===> 任务C");
    }];

    //设置A依赖于B,B依赖于C
    [operationA addDependency:operationB];
    [operationB addDependency:operationC];

    //添加Operation到队列中
    [self.queue addOperations:@[operationA, operationB, operationC] waitUntilFinished:NO];

  现在我们来看一下结果。首先我们看一下不添加依赖时候的结果。我们会发现三个任务之间多次执行之后可能会出现任何的执行顺序。

2016-02-23 21:50:43.255 ThreadDemon[7245:589407] 依赖测试 ===> 任务A
2016-02-23 21:50:43.255 ThreadDemon[7245:589410] 依赖测试 ===> 任务C
2016-02-23 21:50:43.255 ThreadDemon[7245:589409] 依赖测试 ===> 任务B

我们再来看看添加了以来之后的执行结果。我们会发现无论运行多少次肯定都是先执行C,再执行B,最后执行A任务,这样依赖关系就可以得到体现了。

2016-02-23 21:52:59.482 ThreadDemon[7261:591072] 依赖测试 ===> 任务C
2016-02-23 21:52:59.483 ThreadDemon[7261:591070] 依赖测试 ===> 任务B
2016-02-23 21:52:59.483 ThreadDemon[7261:591070] 依赖测试 ===> 任务A

四、NSOperationQueue

这里不对NSOperation进行过多的深入介绍,主要是简单介绍几个常用的方法。

4.1 设置最大并发线程数

  NSOperationQueue提供了方法设置最大可以并发执行的Operation数量。

[_queue setMaxConcurrentOperationCount:5];

4.2 获取当前执行Operation的Queue

NSOperationQueue *queue = [NSOperationQueue currentQueue];

4.3 获取绑定到主线程上的NSOperationQueue对象

NSOperationQueue *queue = [NSOperationQueue mainQueue];

五、Demon源代码

这里给出Github项目上的源代码。
传送门:Github-iOS_Framework_study-ThreadDemon

六、参考资料

  1. 苹果官方文档-NSOperation
  2. 苹果官方文档-NSInvocationOperation
  3. 苹果官方文档-NSBlockOperation
  4. 苹果官方文档-NSOperationQueue
  5. 苹果官方文档-NSInvocation
  6. iOSNSOperationQueue的使用NSInvocation用来呈现objective-C
  7. 多线程编程3 - NSOperationQueue
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值