您的位置:首页 > 运维架构

NSOperation

2015-11-28 17:30 225 查看

NSOperation以及NSOperationQueue的使用

NSOperation vs. GCD

GCD

是一个轻量级,C语言级别的API。由系统来调度。很难定义各个block之间的依赖。如果想要暂停或者取消某个线程需要做额外的工作

NSOperation和NSOperataionQueue

相比较GCD,增加了一些功能,比如可以将一个线程的执行依赖于另外一个线程,而且可以复用,可以取消和暂停。并且NSOperation可以与KVO结合。

线程

线程有两个特点:

每个线程对同一个资源具有相同的访问权限,因此,任何对象都有可能被不同的线程使用,修改。

无法确定一个线程会执行多久,哪个线程会首先完成。

使用线程要解决的问题:

竞争条件(Race Condition):由于每个线程都可以访问相同的内存区域,这就造成了竞争条件。

原子性:

死锁:

睡眠时间:

NSOperation API

创建自定义的opeartion的4个步骤。

继承NSOperation

重写main方法

在main方法中创建自动释放池(autorelease pool)

把你要执行的代码放入自动释放池中

在这里创建一个新的自动释放池的原因是因为你不能对主线程中的自动释放池有任何操作。

在线程操作中,你不知道这个线程将从什么时候开始,也不知道什么时候停止。当用户离开页面时,你不会把一个operation放入后台,所以你可以在main方法中加入
self.isCanceled
来判断是否应该停止执行main中的代码。要取消一个operation,只需调用
cancle
方法即可。

NSOperation还有几个比较关键的方法和属性:

Start:通常不用重写此方法。重写
start
方法通常比较复杂,你必须注意几个属性:isExecuting*,isFinishedisConcurrentisReady。当你将一个opeartion放入一个队列中(queue),队列会调用operation的
start
方法,在执行
main
方法之前做一些准备工作

Dependency:你可以使一个operation依赖于另外一个operation。任何operation都可以依赖于任何数量的operation。例如,operation A依赖于operation B,即使你调用A的
start
方法,operation A也会要等到B执行完成后再开始

Priority:优先级。你可以用
setQueuePriority
方法来设定一个operation在后台执行的优先级。一共有五个级别(优先级从低到高):NSOperationQueuePriorityVerLow,NSOperationQueuePriorityLow,NSOperationQueuePriorityNormal,NSOperationQueuePriorityHigh,NSOperationQueuePriorityVeryHigh

当你把几个operation加到一个队列时,队列会首先遍历所有的operation,从优先级由高到低执行,具有相同优先级的则按照先进先出(FIFO)的规则执行。

CompletionBlock:另外一个非常有用的方法就是
setCompletionBlock:
,当你想执行的代码在后台完成之后,你先进行一些回调操作,那么你就可以把你想指向的操作放到block中,但是注意,block中的代码不一定会在主线程中执行。

operation还有一些需要注意的地方:

如果你想传一些值或者指针到operation,你最好创建自定义的全能初始化方法(designated initializer)

如果你的operation想有返回值,最好使用代理方法。为了不让编译器报错,你需要将代理转为NSObject:

[(NSObject *)self.delegate performSelectorOnMainThread:@selector(delegateMethod:) withObject:object waitUntilDone:NO];


你不能重复的把一个operation加入一个队列,当你把一个operation加入到队列时,你就将失去对这个operation的所有权

一个已经完成的operation无法再重新开始

你取消一个operation并不是马上生效的,只有在某个时间点上检查
isCanclled == YES
时,才会取消这个operation,否则它将会一直执行,直到结束

不管一个operation是否是成功的完成,或者被取消,isFinished属性总会设为YES。所以不要以
isFinished == YES
来判断你需要执行的代码被完全执行

NSOperationQueue API

相比较NSOperation,使用NSOperationQueue则简单得多,你不需要创建一个子类,直接使用它就可以。创建时,最好给队列一个名字,这样就可以在运行时通过这个名字找到这个队列,并且这样也便于调试。

NSOperationQueue *myQueue = [[NSOperationQueue alloc] init];
myQueue.name = @"myQueue";


**Concurrent operations:**NSOperationQueue和线程的概念不一样,一个NSOperationQueue可以包含多个线程。比如有五个NSOperation,每个NSOperation都可以加在这个队列上,而这个队列可以并行的运行这五个线程。

NSOperationQueue会根据特定的平台来决定一次可以运行多少个线程。比如,在系统空闲的时候,NSOperationQueue会运行9个线程,在系统繁忙的时候,NSOperationQueue就只运行2个线程。

最大线程数:你可以设置NSOperationQueue最大同时运行的线程数,当然,根据上面讲的,NSOperationQueue会根据系统状态来选择运行多少个线程,但是最大不会超过你设置的线程数

myQueue.maxConcurrentOperationCount = 3;


添加一个operation:通过以下代码来把一个operation添加到一个队列中

[myQueue addOperation:operation];


线程数:可以通过NSOperationQueue的属性
operations
来获得在队列中等待或者正在运行的线程,也可以通过属性
operationCount
来获取运行的线程数

暂停队列:通过
setSuspended:
方法来暂停或恢复一个队列。

[myQueue setSuspended:YES]; //暂停一个队列,参数为NO则恢复一个队列


取消队列:可以使用方法
cancleAllOperations
方法来取消队列,这个消息实质就是对每个在队列中的operation调用其
cancel
方法,如果一个operation还没有开始,则取消这个operation,并且移除队列,如果一个operation已经开始执行,那么就会取决于前面所讲的,在main方法中识别是否应该取消线程的执行

addOperationBlock:如果你只有一个线程需要执行,那可以使用
addOperationWithBlock
方法来添加你要执行的任务。这时一定要注意是否有循环引用,如果有,记得使用弱引用。记住,要在主线程中执行相应的UI操作。

__weak typeof(self) weakSelf = self //如果会造成循环引用

[myQueue addOperationWithBlock: ^ {
//do something in background
[[NSOperationQueue mainQueue] addOperationWithBlock: ^ {
//do something on main thread
}]
}]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  iOS 多线程 Operation