NSOperation的高级用法

唠嗑

最近开始迁移文章,把以前写的一些文章都迁移到简书,也算开始在简书安家了。

前言

本文是对([WWDC 2015 Session 226: Advanced NSOperations]) 的一个小结,在这个视频中介绍了用NSOperation来组织App中的功能结构,使逻辑更清晰。如果没有看过这个视频可以看看视频,有助于加深对operation的理解。这篇文章更多的是一些理论知识,没什么代码,但是理解一些内部原理有助于平时我们去看第三方库,比如 SDWebImage AFNetworking YYImage等里面对operation自定义的运用。

1.NSOperation 和NSOperationQueue简介

NSOperationQueue是高级的dispatch_queue_t,但同时也提供了一些功能特性供开发者使用。

1.cancelAllOperations:可以取消队列中所有还未执行的operation
2.maxConcurrentOperationCount:最大并行并发数

我们来看一张图

image

如果我们设置maxConcurrentOperationCount=2,我们可以将其看成一个并行队列,同一时刻允许最大的并发数为2。只有上一个operation做完后,下一个operation才会开始。maxConcurrentOperationCount的默认值为default,意思是系统会开设适当数量的子线程。

NSOperation的特点

  1. 可以cancel未执行的operation
  2. 指定相同或者不同队列的依赖关系
  3. kvo监控NSOperation的对象属性
  4. 指定操作优先级
  5. 重用operation:operation只能被执行一次后生命周期就结束了,不能被多次执行。

NSOperation可以看成dispatch_block_t的封装。我们来看看operation 的生命周期(图1),当我们init一个operation,它的初始状态是Pending,然后在某一时刻会到Ready,这时operation从queue中拿出开始执,进入executing状态,最后执行完毕到finished状态。在除finished以外的其它三个状态都可以到cancelled状态。

图1

operation各个状态说明:

Ready:一个operation只有在Ready状态才可以被queue执行。下图,在一个串行的queue中,即使第一次进入Ready状态的operation是在第四个被放进去的,但是还是第一个执行。这样的好处就是,放入串行队列的operation我们不需要在operation定义的时候就确定它的执行顺序,而是在后面动态的确定执行顺序。(控制进入Ready状态的时机)

image

用这个Ready属性我们可以做什么事儿呢?我们可以确定依赖(dependencies)。默认条件下,如果A依赖于B,当A进入finish状态,那么B才会进入Ready状态。这个依赖可以存在于不同的operationQueue。一个operaion直有它依赖的所有operation处于finish状态,它才回进入ready状态。如果我们用queue来管理operation,operation在加入到queue中的某一个时刻,它会在它依赖的operaions执行完毕(或者我们没有设置依赖),在某一个时刻自动进入Ready状态并被执行。当然我们可以手动执行operation,但是官方不推荐,因为调用一个未Ready状态的operation会导致异常抛出。

Cancel:可以cancel未执行的operation,该方法会设置对象内的标志位,表明operation不需要执行,如果operation已经start,就不能取消了。operation进入cancel状态只是一个Bool值的翻转,当我们继承operation,我们要自己决定cancel时候需要做什么业务。比如我们在执行一个网络请求,cancel状态代表着cancel 一个urlSession。当我们请求一个数据库,cancel代表我们停止对数据库进行读写操作。所以我们最好KVO这个属性,然后做适当的逻辑。加入到queue的operaion如果不处于finish状态,可以进入cancel状态。调用[operaion cancel]。默认条件下,operation调用cancel,也会标志它进入finished状态。因为只有这样依赖它的operation才有机会被执行。如果我们自定义operation,我们要考虑它进入cancel状态或者这个operation没有被成功执行时候,根据业务是否应该让它进入finished。

KVO:operation 的状态是满足KVO的,可以被监听,可以被监听的keyPath(isCancelled,isAsynchronous,isExecuting,isFinished,isReady等)。注意:因为operaion可能在任何线程内被执行,如果我们将UI元素和以上属性做绑定,那么KVO过来的行为就可能发生在任何的线程内。保险的做法是:如果KVO得知通知后要做UI的事情,都扔到主线程中做。如果我们在自定义operaion时候重写以上属性,也要确保它们可以被KVO和KVC。

线程安全:系统提供的operaion的子类都是线程安全的,所有用系统的operation我们不需要加锁,当我们自定义operaion,提供一些对外的数据存取的方法自己加锁。

同步和异步的Operaions:

如果我们手动执行一个operation,而不是把它放入一个operationQueue进行管理。operation自己本身也有同步和异步之分,(默认同步)。同步的operation不会开子线程,会在调用start这个方法的线程内执行。而异步的会自己开启子线程,如果我们用queue来管理operaion,我们希望它是同步的,因为queue自己会开子线程,我们只要保证加入queue的operation可以按次序执行就行。

如果我们不想用queue和GCD来管理operation但想要利用子线程执行operation,我们应该自定义一个异步的operation。我们需要追踪operation的状态而且手动触发KVO。或者用KVC触发KVO。其实我们平时在用点语法用系统的setter的时候,它是通过KVC设置的,所以自动会触发KVO通知,如果我们重载了setter,为了让属性符合KVO条件,必须手动触发通知。

image

作为抽象类,我们可以继承NSOpration,实现自己的operation来代码业务逻辑。

同步的operation条件:

1.重载main方法,这个方法里面放主业务逻辑。也需要查看cancel属性

2.如果我们重载了getter和setter,必须确保调用是线程安全的。

异步operation条件:

1.重载start方法,和asynchronous,exciting,finished属性

start方法中我们必须确保operation异步执行,在此方法中我们需要改变executing更新状态,发送executing KVO通知。当结束operation。必须更新isExecuting和isFinished状态,并触发kvo通知。当cancel一个operation时候,我们也要更新isFinished状态,即使此时operation还未执行。在queue 中的operation必须进入cancel状态后才可以被从operation中移除,

注意:start里面不能调用[super start];在自定义异步operation中,我们完全自定义start,已经全部模拟了父类默认的start行为(start task && send KVO),在start方法里面,我们还要查看isCanceled属性,确保start task前,task是不是已经被取消。如果我们自定义了dependency,我们还需要发送isReady的KVO通知。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容