在iOS开发中,为了提升用户体验,我们通常会将操作耗时的操作放在主线程之外的线程进行处理。对于正常的简单操作,我们更多的是选择代码更少的GCD,让我们专注于自己的业务逻辑开发。NSOperation在ios4后也基于GCD实现,但是相对于GCD来说可控性更强,并且可以加入操作依赖。

NSOperation是一个抽象的基类,表示一个独立的计算单元,可以为子类提供有用且线程安全的建立状态,优先级,依赖和取消等操作。系统已经给我们封装了NSBlockOperation和NSInvocationOperation这两个实体类。使用起来也非常简单,不过我们更多的使用是自己继承并定制自己的操作。

NSOperation定义

- (void)start;
- (void)main; @property (readonly, getter=isCancelled) BOOL cancelled;
- (void)cancel; @property (readonly, getter=isExecuting) BOOL executing;
@property (readonly, getter=isFinished) BOOL finished;
@property (readonly, getter=isConcurrent) BOOL concurrent; // To be deprecated; use and override 'asynchronous' below
@property (readonly, getter=isAsynchronous) BOOL asynchronous NS_AVAILABLE(10_8, 7_0);
@property (readonly, getter=isReady) BOOL ready; - (void)addDependency:(NSOperation *)op;
- (void)removeDependency:(NSOperation *)op; @property (readonly, copy) NSArray *dependencies; typedef NS_ENUM(NSInteger, NSOperationQueuePriority) {
NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8
}; @property NSOperationQueuePriority queuePriority; @property (copy) void (^completionBlock)(void) NS_AVAILABLE(10_6, 4_0); - (void)waitUntilFinished NS_AVAILABLE(10_6, 4_0); @property double threadPriority NS_DEPRECATED(10_6, 10_10, 4_0, 8_0); @property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0); @property (copy) NSString *name NS_AVAILABLE(10_10, 8_0);

状态

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

依赖

NSOperation中我们可以为操作分解为若干个小的任务,通过添加他们之间的依赖关系进行操作,这点在设计上是很有意义的。比如我们最常用的图片异步加载,第一步我们是去通过网络进行加载,第二步我们可能需要对图片进行下处理(调整大小或者压缩保存)。我们可以直接调用- (void)addDependency:(NSOperation*)op;这个方法添加依赖:

[imgRsizingOperation addDependency:networkOperation];
[operationQueue addOperation:networkOperation];
[operationQueue addOperation:imgRsizingOperation];

这点我们必须要注意的是不能添加相互依赖,像A依赖B,B依赖A,这样会导致死锁!还有一点必须要注意的时候,在每个操作完成时,请将isFinished设置为YES,不然后续的操作是不会开始执行的。

执行

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

队列是怎么调用我们的执行的操作的呢?如果你只是想弄一个同步的方法,那很简单,你只要重写main这个函数,在里面添加你要的操作。如果想定义异步的方法的话就重写start方法。在你添加进operationQueue中的时候系统将自动调用你这个start方法,这时将不再调用main里面的方法。

取消

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

简单示例代码

最后我们看看一个简单的小示例,在.m文件里面我们将重写finished executing两个属性。我们重写set方法,手动发送keyPath的KVO通知。在start函数中,我们首先判断是否已经取消,如果取消的话,我们将直接return,并将finished设置为YES。如果没有取消操作,我们将_executing设置为YES,表示当前operation正在执行,继续执行我们的逻辑代码。在执行完我们的代码后,别忘了设置operation的状态,将_executing设置为NO,并将finished设置为YES,这样我们就已经很简单的完成了我们的多线程操作任务。

@interface TestOperation ()

@property (nonatomic, assign) BOOL finished;
@property (nonatomic, assign) BOOL executing; @end @implementation TestOperation @synthesize finished = _finished;
@synthesize executing = _executing; - (void)start
{
if ([self isCancelled]) {
_finished = YES;
return;
} else {
_executing = YES;
//start your task; //end your task _executing = NO;
_finished = YES;
}
}
- (void)setFinished:(BOOL)finished {
[self willChangeValueForKey:@"isFinished"];
_finished = finished;
[self didChangeValueForKey:@"isFinished"];
} - (void)setExecuting:(BOOL)executing {
[self willChangeValueForKey:@"isExecuting"];
_executing = executing;
[self didChangeValueForKey:@"isExecuting"];
}

多线程之NSOperation简介的更多相关文章

  1. 多线程之NSOperation

    关于多线程会有一系列如下:多线程之概念解析 多线程之pthread, NSThread, NSOperation, GCD 多线程之NSThread 多线程之NSOperation 多线程之GCD

  2. IOS多线程之NSOperation学习总结

    NSOperation简介 1.NSOperation的作用 配合使用NSOperation和NSOperationQueue也能实现多线程编程 2.NSOperation和NSOperationQu ...

  3. iOS多线程之NSOperation详解

    使用NSOperation和NSOperationQueue进行多线程开发,只要将一个NSOperation(实际开发中需要使用其子类 NSInvocationOperation,NSBlockOpe ...

  4. 多线程之NSOperation和NSOperationQueue

    这篇文章里我将不过多的谈及理论知识,这些东西会的自然会,不会的,看多了也是云里雾里.下面我讲更多的用代码+注释的方式来讲如何使用NSOperation和NSOperationQueue. 1.NSOp ...

  5. iOS-多线程之NSOperation

    前言 这篇文章主要讲NSOperation的使用. What 使用NSOperation和NSOperationQueue进行多线程开发类似于线程池,只要将一个NSOperation(实际开发中需要使 ...

  6. iOS多线程之NSOperation,NSOperationQueue

    使用 NSOperation的方式有两种, 一种是用定义好的两个子类: NSInvocationOperation 和 NSBlockOperation. 另一种是继承NSOperation 如果你也 ...

  7. (五十六)iOS多线程之NSOperation

    NSOpertation是一套OC的API,是对GCD进行的Cocoa抽象. NSOperation有两种不同类型的队列,主队列和自定义队列. 主队列运行于主线程上,自定义队列在后台运行. [NSBl ...

  8. iOS开发多线程之NSOperation

    NSInvocationOperation The NSInvocationOperationclass is a concrete subclass of NSOperationthat you u ...

  9. iOS多线程之NSOperation和NSOperationQueue的使用

    一:NSOperation 两个子类+重写main方法 NSInvocationOperation NSBlockOperation 有个类方法 BlockOprationWith: 还有就是自己个子 ...

随机推荐

  1. docker进入容器内部执行命令

    [root@bogon ~]# docker ps -l CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 38a2cae4c32f jenk ...

  2. HTTP请求重复发送

    帖子地址 http://bbs.csdn.net/topics/390831787 解决方案:1.  java -Dsun.net.http.retryPost=false 2. 换用apche ht ...

  3. Linux使用sleep进行延迟实验

    sleep命令可以延迟脚本执行一段时间(以秒为单位).下面的命令使用tput和sleep从0开始计时到40秒: #/bin/bash echo Count: tput sc # 循环40s for c ...

  4. robot:根据条件主动判定用例失败或者通过

    场景: 当用例中的断言部分需要满足特定条件时才会执行,如果不满足条件时,可以主动判定该用例为passed状态,忽略下面的断言语句. 如上图场景,当每月1号时,表中才会生成上月数据,生成后数据不会再有改 ...

  5. docker 使用阿里云镜像加速

    1.登录阿里云 2.进入控制台 3.搜索 “容器镜像服务” 下拉点击 “镜像加速器” 复制自己的私有地址 进入自己的docker宿主机器(替换下面的地址为自己的私有地址) 修改daemon配置文件/e ...

  6. 浅谈PHP随机数安全的分析

    之前在身边有很多学PHP的朋友写一些小程序的时候,很多时候会使用PHP随机数函数rand()和mt_rand()函数去生成随机数 可是,随机数真的随机吗?这篇文章讲从多个实例中探讨随机数,当然,有写作 ...

  7. JVM(二) 栈内存结构

    栈内存是描述java方法执行的内存模型,每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表.操作数栈.动态链接.返回出口等信息.每一个方法从调用直至执行完成的过程,就对应 ...

  8. Python数据挖掘之随机森林

    主要是使用随机森林将four列缺失的数据补齐. # fit到RandomForestRegressor之中,n_estimators代表随机森林中的决策树数量 #n_jobs这个参数告诉引擎有多少处理 ...

  9. php高级研发或架构师必了解---面试题系列

    近接连面试了几家公司,有些重要问题记录一下,督促自己学习提高,同时希望给朋友们一些帮助. 内容很多,一点点完善,一步步学习.. 有些是面试被问,有些是招聘要求,有些是自己整理加的. 一.mysql相关 ...

  10. scrapy工具创建爬虫工程

    1.scrapy创建爬虫工程:scrapy startproject scrape_project_name >scrapy startproject books_scrapeNew Scrap ...