美文网首页
iOS多线程之NSoperation

iOS多线程之NSoperation

作者: comst | 来源:发表于2016-04-10 22:46 被阅读178次

    iOS多线程之NSoperation

    目前在 iOS 和 OS X 中有两套先进的同步 API 可供我们使用:NSOperation 和 GCD 。其中 GCD 是基于 C 的底层的 API ,而 NSOperation 则是 GCD 实现的 Objective-C API。 虽然 NSOperation 是基于 GCD 实现的, 但是并不意味着它是一个 GCD 的“dumbed-down” 版本, 相反,我们可以用NSOperation 轻易的实现一些 GCD 要写大量代码的事情。
    NSOperation是一个抽象的基类,表示一个独立的计算单元,可以为子类提供有用且线程安全的建立状态,优先级,依赖和取消等操作。系统已经给我们封装了NSBlockOperation和NSInvocationOperation这两个实体类。使用起来也非常简单,不过我们更多的使用是自己继承并定制自己的操作。

    状态

    NSOperation提供了ready cancelled executing finished这几个状态变化,我们的开发也是必须处理自己关心的其中的状态。这些状态都是基于keypath的KVO通知决定,所以在你手动改变自己关心的状态时,请别忘了手动发送通知。这里面每个属性都是相互独立的,同时只可能有一个状态是YES。finished这个状态在操作完成后请及时设置为YES,因为NSOperationQueue所管理的队列中,只有isFinished为YES时才将其移除队列,这点在内存管理和避免死锁很关键。

    依赖

    NSOperation中我们可以为操作分解为若干个小的任务,通过添加他们之间的依赖关系进行操作,这点在设计上是很有意义的。比如我们最常用的图片异步加载,第一步我们是去通过网络进行加载,第二步我们可能需要对图片进行下处理(调整大小或者压缩保存)。我们可以直接调用- (void)addDependency:(NSOperation*)op;
    这点我们必须要注意的是不能添加相互依赖,像A依赖B,B依赖A,这样会导致死锁!还有一点必须要注意的时候,在每个操作完成时,请将isFinished设置为YES,不然后续的操作是不会开始执行的。

    执行

    执行一个operation有两种方法,第一种是自己手动的调用start这个方法,这种方法调用会在当前调用的线程进行同步执行,所以在主线程里面自己一定要小心的调用,不然就会把主线程给卡死。
    第二种是将operation添加到operationQueue中去,这个也是我们用得最多的也是提倡的方法。NSOperationQueue会在我们添加进去operation的时候尽快进行执行。当然如果NSOperationQueue的maxConcurrentOperationCount如果设置为1的话,进相当于FIFO了。

    取消

    NSOperation允许我们调用-(void)cancel取消一个操作的执行。当然,这个操作并不是我们所想象的取消。这个取消的步骤是这样的,如果这个操作在队列中没有执行,那么这个时候取消并将状态finished设置为YES,那么这个时候的取消就是直接取消了。如果这个操作已经在执行了,那么我们只能等其操作完成。当我们调用cancel方法的时候,他只是将isCancelled设置为YES。所以,在我们的操作中,我们应该在每个操作开始前,或者在每个有意义的实际操作完成后,先检查下这个属性是不是已经设置为YES。如果是YES,则后面操作都可以不用在执行了。

    completionBlock

    iOS4后添加了这个block,在这个操作完成时,将会调用这个block一次,这样也非常方便的让我们对view进行更新或者添加自己的业务逻辑代码。

    优先级

    operationQueue有maxConcurrentOperationCount设置,当队列中operation很多时而你想让后续的操作提前被执行的时候,你可以为你的operation设置优先级。
    NSOperationQueuePriorityVeryLow = -8L,
    NSOperationQueuePriorityLow = -4L,
    NSOperationQueuePriorityNormal = 0,
    NSOperationQueuePriorityHigh = 4,
    NSOperationQueuePriorityVeryHigh = 8

    使用
    • 通过SDK自带的NSBlockOperation和NSInvocationOperation。
    • 自定义NSOperation的子类。
    NSBlockOperation和NSInvocationOperation

    其实除非必要,简单的工作完全可以使用官方提供的NSOperation两个NSInvocationOperation和NSBlockOperation来实现。
    NSInvocationOperation:
    NSInvocationOperation* theOp = [[NSInvocationOperation alloc]
    initWithTarget:self
    selector:@selector(myTaskMethod:)
    object:data];
    NSBlockOperation:
    NSBlockOperation* theOp = [NSBlockOperation blockOperationWithBlock: ^{
    NSLog(@"Beginning operation.\n");
    // Do some work.
    }];

    自定义NSOperation 的子类

    对于非并发的工作,只需要实现NSOperation子类的main方法。
    -(void)main
    {
    @try
    {
    // 处理工作任务
    }
    @catch(...)
    {
    // 处理异常,但是不能再重新抛出异常
    }
    }
    由于NSOperation的工作是可以取消Cancel的,那么你在main方法处理工作时就需要不断轮询[self isCancelled]确认当前的工作是否被取消了。
    如果要支持并发工作,那么NSOperation子类需要至少override这四个方法:

    • start
    • isConcurrent
    • isExecuting
    • isFinished
      注意你的实现要发出合适的KVO通知,因为如果你的NSOperation实现需要用到工作依赖从属特性,而你的实现里没有发出合适的“isFinished”KVO通知,依赖你的NSOperation就无法正常执行。NSOperation支持KVO的属性有:
      • isCancelled
      • isConcurrent
      • isExecuting
      • isFinished
      • isReady
      • dependencies
      • queuePriority
      • completionBlock

    相关文章

      网友评论

          本文标题:iOS多线程之NSoperation

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