文档章节

NSOperation那些事

dashL
 dashL
发布于 2014/04/11 17:51
字数 1897
阅读 386
收藏 1

iOS中多线程编程主要有三种方式,1)Thread,2)NSOperation与NSOperationQueue,3)GCD,本文简要的介绍一下我理解中的Thread和NSOperation与NSOperationQueue,重点在于介绍NSOperation和NSOperationQueue~

1)NSThread

NSThread,主要有三种创建方式,

- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument
+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument
- (void)performSelectorInBackground:(SEL)selector withObject:nil];

前面两种会显示的创建一个Thread,后一种方法则是NSObject (NSThreadPerformAdditions)的实例方法,当调用这种方法的时候,系统会隐式的创建一个Thread。

Thread的缺点是使用者必须手动去管理,并通过加锁等方式确保线程同步,iOS中有两种加锁方式,即NSLock与NSCondition,之后又通过@synchronized替代了NSLock复杂的书写方式,确保线程同步。

NSThread通过以下四种方式进行线程之间的通信。

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array NS_AVAILABLE(10_5, 2_0);
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);

2)NSOperation

NSOperation是一个基类,你可以通过继承的方式,独立创建子Operation,或者通过实例化NSBlockOperation或者NSInvocationOperation使用operation。

查看NSOperation的官方文档,对下面property及method进行解释。

1)- (id)init;//NSOperation实例初始化方法,用于创建一个NSOperation实例。
2)- (void)start;//该方法是operation的起点,如果需要创建并发operation必须,覆盖start方法。同时调用start方法,会默认做各种验证。
3)- (BOOL)isCancelled;//该property,是用于标示某个operation是否cancel。对于多线程来说需要不断检测这个值。
4)- (void)cancel;//调用cancel方法会取消一个operation,但是如果operation加入到Queue中或者operation已经start了,则无法取消成功,调用cancel也不一定立即执行cancel操作,需要等待时间周期。
5)- (BOOL)isExecuting;//判定operation是否正在执行。
6)- (BOOL)isFinished;//判定operation是否完成,cancel掉某个operation,也会将该operation的该字段设置成为YES。
7)- (BOOL)isConcurrent;//判定该线程是否是并发线程,即调用该operation的start方法的线程是否与operation所在线程相同。
8)- (BOOL)isReady;//在start方法开始之前,需要确定operation是否ready,默认为YES,如果该operation没有ready,则不会start。
9)- (void)addDependency:(NSOperation *)op;//该方法用于配置operation之间的依赖关系,涉及执行顺序稍后会介绍。如果不是手动调用start去执行operation,一定要在将其加入到Queue之前做好依赖,因为一旦加入到Queue中,其也许很快会执行,依赖关系将不会起作用。
10)- (void)removeDependency:(NSOperation *)op;//相对应add,其为移除两个operation之间的依赖关系。
11)- (NSArray *)dependencies;//获取operation的依赖关系的数组。
12)- (NSOperationQueuePriority)queuePriority;//如果将operation加入到Queue中,设定其在Queue中的优先级,优先级高的先执行的概率大,但并不代表一定会先执行,执行顺序稍后介绍。
13)- (void)setQueuePriority:(NSOperationQueuePriority)p;//setter方法。
14)- (void (^)(void))completionBlock NS_AVAILABLE(10_6, 4_0);//在operation完成之后会调用completionBlock,你可以自定义执行行为。
15)- (void)setCompletionBlock:(void (^)(void))block NS_AVAILABLE(10_6, 4_0);//setter方法
16)- (void)waitUntilFinished NS_AVAILABLE(10_6, 4_0);//设定是否等待operation执行结束,如果为YES,该线程会一直等待operation执行结束,才会执行接下来的代码。
17)- (double)threadPriority NS_AVAILABLE(10_6, 4_0);//设定operation的线程优先级,涉及执行顺序稍后介绍。线程优先级默认为0.5,最低为0,最大为1.即使设定了线程优先级,也只能保证其在main方法范围内有效,operation的其他代码仍然执行在默认线程。
18)- (void)setThreadPriority:(double)p NS_AVAILABLE(10_6, 4_0);setter方法。

手动创建Operation

1)非并发Operation

如果该operation为非并发operation,则只需要重写其main方法,并正确的执行cancel操作即可,需要operation定时检测isCanceled值。

2)并发Operation

如果需要创建一个并发的Operation,并手动执行,则需要重写main,start,isCancelled,isReady,isConcurrent,isFinished,isExcluting,dependency,queuepripority方法,并维护每个property的KVO,同时确保每个property的原子性。

利用NSInvocationOperation或者NSBlockOperation

大多数开发都不需要自己独立创建operation,而只需要创建一个invocationOperation实例或者创建一个BlockOperation实例,之后将其加入到OperationQueue中,网上很多例子,不再赘述。需要注意的一点是,你应该尽量持有operation的引用,而不要让operation的block做数据存储操作,因为operation的线程被Queue持有,而不是自己独立管理线程。

3)NSOperationQueue

你可以假想成NSOperationQueue是一个任务管理队列,你只需要封装好每个任务(operation),然后将其加入到OperationQueue中,其就会在某个时间执行。

- (void)addOperation:(NSOperation *)op;
- (void)addOperations:(NSArray *)ops waitUntilFinished:(BOOL)wait NS_AVAILABLE(10_6, 4_0);
- (void)addOperationWithBlock:(void (^)(void))block NS_AVAILABLE(10_6, 4_0);

上述三种方式,就是将operation加入到queue中,你可以不断的将operation加入到queue中,但是如果operation加入的过多,则调度operation所耗费的时间会大大增加,导致系统性能下降。

- (NSInteger)maxConcurrentOperationCount;//设定queue的最大并发数
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;//setter方法
- (void)setSuspended:(BOOL)b;//设置queue是否挂起,YES为将该Queue挂起,NO则取消挂起。如果一个queue处于挂起状态,则其不会相应启动任何operation,如果碰巧operation的waituntilfinished设置成为YES,则陷入死锁。
- (BOOL)isSuspended;//判定某个queue是否挂起
- (void)cancelAllOperations;//取消所有operations
- (void)waitUntilAllOperationsAreFinished;//等待所有的operations执行结束
+ (id)currentQueue NS_AVAILABLE(10_6, 4_0);//获取当前的queue
+ (id)mainQueue NS_AVAILABLE(10_6, 4_0);//获取主线程的queue

4)执行顺序

主要介绍所有operation放在同一个Queue中的执行顺序。先上一段测试代码。

NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        self.count += 2;
        NSLog(@"o1:%d",self.count);
    }];
    [operation setCompletionBlock:^{
        NSLog(@"o1,finished");
    }];
    NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
        self.count += 1;
        NSLog(@"o2:%d",self.count);
    }];
    [operation2 setCompletionBlock:^{
        NSLog(@"o2,finished");
    }];
    [operation2 addDependency:operation];
    NSOperationQueue *operationQ = [[NSOperationQueue alloc] init];
    [operation2 setQueuePriority:NSOperationQueuePriorityHigh];
    [operation setThreadPriority:0];
    operationQ.maxConcurrentOperationCount = 1;
    NSArray *array = @[operation,operation2];
    [operationQ addOperations:array waitUntilFinished:YES];

在实例代码中,首先设定Queue为单队列,即最大并发数为1。此时主要有两个考虑因素,首先考虑Operation的依赖关系,

[operation2 addDependency:operation];

Operation2依赖于Operation,所以一定是Operation先执行,之后继续执行Operation2,如果将这行代码注释掉,则开始考虑Operation之间的QueuePriority,在本例子中

 [operation2 setQueuePriority:NSOperationQueuePriorityHigh];

Operation2的queuePriority高于Operation,故先执行Operation2,之后再执行Operation,如果再将这行代码注释掉,则考虑加入的先后顺序

 NSArray *array = @[operation,operation2];

operation先于operation2,则会先执行operation,之后再执行operation2。threadPriority,只会影响其在具体线程资源的priority,并不会影响queue的调度顺序。

假设在本例中的OperationQueue的最大并发数为2,则仍然是按照此顺序调度,不过由于最大并发数为2,假设去除依赖关系,所以operation与operation2需要看谁先轮到时间片,谁先谁后则不确定,如果仍旧存在依赖关系,仍旧是operation先执行,operation2后执行,但是哪个先执行完成并不确定。

ps:在本例中采用了blockOperation方式,同时在block中引用了self.count,并将其值打印出来,可以看到其值是乱的,多线程,你还能要求神马呢。。欢迎交流~~

© 著作权归作者所有

共有 人打赏支持
dashL
粉丝 0
博文 5
码字总数 3765
作品 0
哈尔滨
程序员
NSOperation 简介和应用

基本介绍 NSBlockOperation 打印内容 打印纪录 取消操作 [operation cancel]; NSOperation的依赖关系 MyDownloadOperation downloadOp = [[MyDownloadOperation alloc] init]; // MyDownload......

云飞扬v5
2016/11/12
1
0
操作抽象设计-实践

前言 最近在做程序优化和代码总结的工作,在优化和总结的过程中发现,程序中存在着许多重复性的交互代码,特别是在业务逻辑层,虽然业务模块本身具有独立性,各业务模块之间也有比较明确的分...

Delpan
2017/12/18
0
0
并发程序设计——Operation Queues(操作队列)

Cocoa operations以面向对象的形式封装程序中的工作单元,提供异步执行机制。Operations可以独立运行,也可以与Operation Queue协同运行。OS X和IOS中Cocoa应用程序大多运用了operation机制。...

big军
2013/06/04
0
0
iOS多线程之NSOperation

1.简介 1.1NSOperation的作用 配合使用NSOperation和NSOperationQueue也能实现多线程编程 1.2NSOperation和NSOperationQueue实现多线程的具体步骤 先将需要执行的操作封装到一个NSOperation...

JlongTian
2016/01/10
33
0
【iOS】多线程NSOperation

NSOperation是苹果封装的一套多线程的东西,不像GCD是纯C语言的,这个是OC的。但相比较之下GCD会更快一些,但本质上NSOPeration是多GDC的封装。 一、NSOperation与GCD的比较 GCD是基于c的底层...

xn4545945
2014/07/28
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Python介绍

Python介绍 一、简介 Python是完全面向对象的语言。函数、模块、数字、字符串都是对象。并且完全支持继承、重载等,有益于增强源代码的复用性。Python相对于Lisp这种传统的函数式编程语言,P...

星汉
14分钟前
0
0
VS_设置护眼背景色

工具---->选项---->环境---->字体和颜色:

一个小妞
17分钟前
0
0
Flask跨域请求的处理方法

在Flask开发RESTful后端时,前端请求会遇到跨域的问题。下面是解决方法: 使用 flask-cors库可以很容易的解决 pip install flask-cors 两种方法,一个是全局/批量的,一个是单一独立的: 安全...

ykbj
18分钟前
2
0
Pandas学习记录-Series

系列(Series)是能够保存任何类型的数据(整数,字符串,浮点数,Python对象等)的一维标记数组。轴标签统称为索引。 pandas.Series Pandas系列可以使用以下构造函数创建 - pandas.Series( dat...

kipeng300
25分钟前
0
0
可以实现内网穿透的几款工具

最近没什么事情,看了一些关于内网穿透的文章,因我本身已是做微信开发相关的工作,对这部分关注的比较多,现分享给大家。 首先说下内网穿透的原理。 NAPT原理 在NAT网关上会有一张映射表,表...

哥本哈根的小哥
27分钟前
23
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部