文档章节

NSOperation那些事

dashL
 dashL
发布于 2014/04/11 17:51
字数 1897
阅读 388
收藏 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,并将其值打印出来,可以看到其值是乱的,多线程,你还能要求神马呢。。欢迎交流~~

© 著作权归作者所有

共有 人打赏支持
上一篇: GCD,come on!
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
iOS之[多线程:NSOperation]

NSOperation :fa-exclamation-triangle:以下是你需要考虑使用 NSOperation 的一些理由: 1.当你需要取消线程任务时,GCD 无法提供取消任务的操作。而 NSOperation 提供了取消任务的操作; 2.当...

言筱羽
2015/11/23
95
0
并发程序设计——Operation Queues(操作队列)

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

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

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

xn4545945
2014/07/28
0
0

没有更多内容

加载失败,请刷新页面

加载更多

java框架学习日志-2

上篇文章(java框架学习日志-1)虽然跟着写了例子,也理解为什么这么写,但是有个疑问,为什么叫控制反转?控制的是什么?反转又是什么? 控制其实就是控制对象的创建。 反转与正转对应,正转...

白话
23分钟前
0
0
Integer使用双等号比较会发生什么

话不多说,根据以下程序运行,打印的结果为什么不同? Integer a = 100;Integer b = 100;System.out.println(a == b);//print : trueInteger a = 200;Integer b = 200;System.out.pr...

兜兜毛毛
昨天
8
0
CockroachDB

百度云上的CockroachDB 云数据库 帮助文档 > 产品文档 > CockroachDB 云数据库 > 产品描述 开源NewSQL – CockroachDB在百度内部的应用与实践 嘉宾演讲视频及PPT回顾:http://suo.im/5bnORh ...

miaojiangmin
昨天
4
0
I2C EEPROM驱动实例分析

上篇分析了Linux Kernel中的I2C驱动框架,本篇举一个具体的I2C设备驱动(eeprom)来对I2C设备驱动有个实际的认识。 s3c24xx系列集成了一个基于I2C的eeprom设备at24cxx系列。at24cxx系列芯片包...

yepanl
昨天
5
0
设计模式之工厂模式

本篇博文主要翻译这篇文章: https://www.journaldev.com/1392/factory-design-pattern-in-java 由于翻译水平有限,自认为许多地方翻译不恰当,欢迎各位给出宝贵的建议,建议大家去阅读原文。...

firepation
昨天
14
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部