NSOperation

在生活中过,经常有许多工作要做。每天有固定的任务流程,这些流程充斥着我们的工作时间。

但是不管一个人的任务有多重,在面对IOS app的负载时,这些任务将变得苍白无力。因为IOS app要执行数以亿计的计算,同时每16亿秒的速度管理着绘制任务。
编程中的生产率,就如生活中的一样,是一种计划、优先和多任务一起存在的一种关系。

使程序变快的秘籍就是尽可能的降低不需要的工作到后台去,在这方面,现代的Cocoa developer有两个选择:Grand Central DispatchNSOperation。这篇文章将主要关注于后者,尽管这两者或多或少是相辅相成的。


NSOperation表示一个单一的工作单元。它是个抽象类,能够提供有用的,线程安全的结构体来模型化状态,优先权,独立性和管理这些内容。

很多情况下不需要建立一个NSOperation的子类,Foundation提供了2个具体实现类NSBlockOperation和NSInvocationOperation。

一般需要用到NSOperation的例子包括网络请求,图像的重新绘制,文字处理,或者任何重复性的,结构性的,长时间运行的任务
但是由于一个对象不能够做太多的计算,从而NSOperation就诞生了

NSOperationQueue

NSOperationQueue规定并发执行任务。它和优先队列很像,任务大致以先进先出的方式执行,同时高优先权的任务会比低优先权的任务线执行,NSOperationQueue也能够限制最大的并发数,使用maxConcurrentOperationCount来设置。

NSOperationQueue可以回溯到Grand Central Dispatch,尽管它有自己独立的实现。

为了使NSOperation能够开始运行,要么使用start,要么把它增加到NSOperationQueue中去,它将在到达去队列最前面的时候开始执行。因为在NSOperationQueue中的NSOperation能够获得很多好处,所以绝大多数情况下是把NSOperation加入到NSOperationQueue中去,而不是直接start执行。

state

NSOperation以一种相当优雅的state编码来描述一个操作的执行。

ready -> executing -> finished

代替显示地设置state,state是通过KVO通知的形式来隐式的设置键的。当一个操作准备执行时,它将为ready键发送一个KVO通知,然后设置为true。
每一个特性都必须是于其他的特性互斥的,从而保持一致性。

ready:来表明操作是准备执行了,返回true,如果还没完成初始化,将返回false。
executing:如果正在执行一个任务,返回true,否则返回false。
finished:如果一个操作任务成功完成或者取消,返回true。NSOperationQueue不会将操作移除队列,知道finished被改为true,因此执行正确的子类来避免死循环是至关重要的。

Cancellation

尽早的取消任务来阻止不需要的工作被执行是很有必要的,不管是因为在一个独立的操作中的失败或者是被用户取消。

与执行状态很相似,NSOperation通过KVO来设置cancell的键。当一个操作是被取消时,应该清理任何内部的细节,从而尽快的到达finished状态。特别是cancelled和finished都需要被设置为true,同时exectuing需要被置为false。

Priority

所有的操作可能不是同等重要的,设置队列优先权将会提高或降低一个操作的优先权。

enum NSOperationQueuePriority : Int {
    case VeryLow
    case Low
    case Normal
    case High
    case VeryHigh
}

Quality of Service

服务质量是一个新的概念在IOS8和OS X Yosemite中,它创建了一个一致性的,高等级的语言来安排系统资源。 在XPC and NSOperation中都介绍了APIs如何使用。

对于NSOperation,threadPriority属性是过时的,替代的是qualityOfService属性。(threadPriority对于大多数开发者而言是太沉重了。)

以下的枚举值被用来表示自然的不急促的操作。应用鼓励选择最恰当的值来确保一个最大的使用体验。

enum NSQualityOfService : Int {
    case UserInteractive
    case UserInitiated
    case Utility
    case Background
    case Default
}
  • .UserInteractive:UserInteractive是直接用于与UI交互的操作,比如说进程事件或者在屏幕上绘制。
  • .UserInitiated:UserInitiated是被用于用户显式的请求的工作,这个结果必须立即呈现为了更近一步的交互。比如说,用户在消息列表中选择了一个email,那么这个email必须立即加载。
  • .Utility:Utility是被用于用户不可能立即等待这个结果的操作。这个操作可能是用户请求的,也可能是自动初始化的,不阻止用户进一步的交互,它经常会有一个进度条来显示时间进度。这个任务将以一个比较效率的方式执行,当资源被限制的时候,它将执行比较高的QoS工作。比如说,大的文件操作(media输入)或周期性的内容跟新。
  • .Background:Background是用在不是用户初始化或者可见的操作中。一般来说,既使这个操作被执行,用户也不知道。当给予它更高的QoS工作任务时,它将以最快的效率方式执行。比如说,预抓取内容,搜索索引,备份,外部系统的同步数据。
  • .Default:Default表示缺失QoS信息。不管什么时候,可能的QoS信息将被从其他资源中推断出来。如果推断不出来,QoS将会在UserInitiated和Utility中选择。
                                                    swift
let backgroundOperation: NSOperation = NSOperation()
backgroundOperation.queuePriority = .Low
backgroundOperation.qualityOfService = .Background

let operationQueue = NSOperationQueue.mainQueue()
operationQueue.addOperation(backgroundOperation)

Asynchronous Operations

另外一个在IOS8和OS X Yosemite的改变是concurrent的过时,替代的是新的asynchronous属性。

起初,concurrent属性是被用来区分那些只在单一的主线程中工作的操作和那些异步执行他们的自己的state的操作。这个属性同样是用来决定NSOperationQueue是否将在其他的线程执行。在NSOperationQueue不是直接管理自己的线程,而是通过内部分发队列来执行的时候,这个属性将会被忽略。这个新的asynchronous属性清除了concurrent,从而是唯一的决定一个NSOperation是否将被异步执行。

Dependencies

依据应用的复杂性,需要把大的任务拆分成一系列可以拆分的子任务。这就是NSOperation的dependencies所做的事。

举例来说,为了实现从服务器下载和改变图片的大小进程,可以把网络工作区分为一个操作,改变大小是另外一个操作(或许复用网络操作来下载其他资源,或者复用该改变大小的操作来对在缓存中的图片进行处理)。不管怎样,因为一张图片不能被改变大小直到它被下载下来,然后网络操作是依赖于改变大小的操作,因此必须在改变大小操作之前完成网络操作。

let networkingOperation : NSOperation = ...
let resizingOperation : NSOperation = ...
resizingOperation.addDependency(networkingOperation)

let operationQueue = NSOperationQueue.mainQueue()
operationQueue.addOperations([networkingOperation, resizingOperation], waitUntilFinished: false)

一个操作不会开始直到所有的它的依赖是被返回true。

确保没有创建依赖环,比如说a依赖b,b以来a,这将会创建死锁。

completionBlock

当一个NSOperation完成了,它将会执行它的completionBlock一次。这提供一个非常好的方法来定制操作行为,当被使用在一个模型或者视图控制器中。

let operation = NSOperation()
operation.completionBlock = {
    println("Completed")
}

NSOperationQueue.mainQueue().addOperation(operation)

比如说,你可以设置一个网络操作的完成块来做一些从服务器返回的数据处理操作。


NSOperation仍旧是iOS和OS X开发者必不可少的工具。虽然在线性的异步处理方面GCD是理想的,但是NSOperation 提供了更加全面的,面向对象的计算模型来应对所有的结构化的数据,重复性的任务的操作。

开发者在应对各种可能的问题时,应该使用更高等级的抽象。对于安排一些持续性的,重复的工作,应该使用NSOperation。其他时候,可能GCD会更加有效。

When to Use Grand Central Dispatch

分发队列,组,信号量,源和栅栏是并发的必要组成部分,所有的系统框架建立在这之上。

对于一次性的计算,或者简单的加速某个存在的方法,使用轻量级的GCD分发将会更加合适

When to Use NSOperation

NSOperation能够使用一系列依赖在一个特殊的优先队列和服务质量上,从而安排任务。不像GCD队列上的块,NSOperation能够取消操作和询问状态。并且通过基类,NSOperation能够与它自己的结果相联系起来,从而实现将来的引用。


记住一点:NSOperation和Grand Central Dispatch不是互斥的。创新和有效的使用两者是使一个应用健壮的关键。


原文链接:http://nshipster.com/nsoperation/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值