我們都知道,讓程序瞬間加載并且快速響應(yīng)的秘訣在于后臺異步執(zhí)行任務(wù)郎哭。
現(xiàn)在的Objective-C開發(fā)者一般有兩個選擇他匪,分別是Grand Central Dispatch或者NSOperation。現(xiàn)在GCD已經(jīng)逐漸發(fā)展成主流了夸研,所以我們來談?wù)労笳甙蠲郏粋€面向?qū)ο蟮慕鉀Q辦法。
NSOperation表示了一個獨立的計算單元亥至。作為一個抽象類悼沈,它給了它的子類一個十分有用而且線程安全的方式來建立狀態(tài)、優(yōu)先級姐扮、依賴性和取消等的模型絮供。或者茶敏,你不是很喜歡再自己繼承NSOperation的話壤靶,框架還提供NSBlockOperation,這是一個繼承自NSOperation且封裝了block的實體類惊搏。
很多執(zhí)行任務(wù)類型的案例都很好的運用了NSOperation贮乳,包括網(wǎng)絡(luò)請求忧换,圖像壓縮,自然語言處理或者其他很多需要返回處理后數(shù)據(jù)的塘揣、可重復(fù)的包雀、結(jié)構(gòu)化的宿崭、相對長時間運行的任務(wù)亲铡。
但是僅僅把計算封裝進一個對象而不做其他處理顯然沒有多大用處,我們還需要NSOperationQueue來大顯身手葡兑。
NSOperationQueue控制著這些并行操作的執(zhí)行奖蔓,它扮演者優(yōu)先級隊列的角色,讓它管理的高優(yōu)先級操作(NSOperation -queuePriority)能優(yōu)先于低優(yōu)先級的操作運行的情況下讹堤,使它管理的操作能基本遵循先進先出的原則執(zhí)行吆鹤。此外,在你設(shè)置了能并行運行的操作的最大值(maxConcurrentOperationCount)之后洲守,NSOperationQueue還能并行執(zhí)行操作疑务。
讓一個NSOperation操作開始,你可以直接調(diào)用-start梗醇,或者將它添加到NSOperationQueue中知允,添加之后,它會在隊列排到它以后自動執(zhí)行叙谨。
現(xiàn)在讓我們通過怎樣使用和怎樣通過繼承實現(xiàn)功能來看看NSOperation稍微復(fù)雜的部分温鸽。
狀態(tài)
NSOperation包含了一個十分優(yōu)雅的狀態(tài)機來描述每一個操作的執(zhí)行。
isReady → isExecuting → isFinished
為了替代不那么清晰的state屬性手负,狀態(tài)直接由上面那些keypath的KVO通知決定涤垫,也就是說,當(dāng)一個操作在準(zhǔn)備好被執(zhí)行的時候竟终,它發(fā)送了一個KVO通知給isReady的keypath蝠猬,讓這個keypath對應(yīng)的屬性isReady在被訪問的時候返回YES。
每一個屬性對于其他的屬性必須是互相獨立不同的统捶,也就是同時只可能有一個屬性返回YES榆芦,從而才能維護一個連續(xù)的狀態(tài): - isReady: 返回 YES 表示操作已經(jīng)準(zhǔn)備好被執(zhí)行, 如果返回NO則說明還有其他沒有先前的相關(guān)步驟沒有完成。 - isExecuting: 返回YES表示操作正在執(zhí)行瘾境,反之則沒在執(zhí)行歧杏。 - isFinished : 返回YES表示操作執(zhí)行成功或者被取消了,NSOperationQueue只有當(dāng)它管理的所有操作的isFinished屬性全標(biāo)為YES以后操作才停止出列迷守,也就是隊列停止運行犬绒,所以正確實現(xiàn)這個方法對于避免死鎖很關(guān)鍵。
取消
早些取消那些沒必要的操作是十分有用的兑凿。取消的原因可能包括用戶的明確操作或者某個相關(guān)的操作失敗凯力。
與之前的執(zhí)行狀態(tài)類似茵瘾,當(dāng)NSOperation的-cancel狀態(tài)調(diào)用的時候會通過KVO通知isCancelled的keypath來修改isCancelled屬性的返回值,NSOperation需要盡快地清理一些內(nèi)部細(xì)節(jié)咐鹤,而后到達一個合適的最終狀態(tài)拗秘。特別的,這個時候isCancelled和isFinished的值將是YES祈惶,而isExecuting的值則為NO雕旨。
有一件肯定需要注意的事情就是關(guān)于單詞"cancel"的拼法特性,盡管各類英語的習(xí)慣不盡相同捧请,但是對于NSOperation來說: - cancel: 方法調(diào)用里只需要一個L(動詞) - isCancelled: 屬性里需要兩個L(形容詞)
優(yōu)先級
不可能所有的操作都是一樣重要凡涩,通過以下的順序設(shè)置queuePriority屬性可以加快或者推遲操作的執(zhí)行:
NSOperationQueuePriorityVeryHigh
NSOperationQueuePriorityHigh
NSOperationQueuePriorityNormal
NSOperationQueuePriorityLow
NSOperationQueuePriorityVeryLow
此外,有些操作還可以指定threadPriority的值疹蛉,它的取值范圍可以從0.0到1.0活箕,1.0代表最高的優(yōu)先級。鑒于queuePriority屬性決定了操作執(zhí)行的順序可款,threadPriority則指定了當(dāng)操作開始執(zhí)行以后的CPU計算能力的分配育韩,如果你不知道這是什么,好吧闺鲸,你可能根本沒必要知道這是什么筋讨。
依賴性
根據(jù)你應(yīng)用的復(fù)雜度不同,將大任務(wù)再分成一系列子任務(wù)一般都是很有意義的翠拣,而你能通過NSOperation的依賴性實現(xiàn)版仔。
比如說,對于服務(wù)器下載并壓縮一張圖片的整個過程误墓,你可能會將這個整個過程分為兩個操作(可能你還會用到這個網(wǎng)絡(luò)子過程再去下載另一張圖片蛮粮,然后用壓縮子過程去壓縮磁盤上的圖片)。顯然圖片需要等到下載完成之后才能被調(diào)整尺寸谜慌,所以我們定義網(wǎng)絡(luò)子操作是壓縮子操作的依賴然想,通過代碼來說就是:
[resizingOperation addDependency:networkingOperation];
[operationQueue addOperation:networkingOperation];
[operationQueue addOperation:resizingOperation];
除非一個操作的依賴的isFinished返回YES,不然這個操作不會開始欣范。時時牢記將所有的依賴關(guān)系添加到操作隊列很重要变泄,不然會像走路遇到一條大溝,就走不過去了喲恼琼。
此外妨蛹,確保不要意外地創(chuàng)建依賴循環(huán),像A依賴B晴竞,B又依賴A蛙卤,這也會導(dǎo)致杯具的死鎖。
completionBlock
有一個在iOS 4和Snow Leopard新加入的十分有用的功能就是completionBlock屬性。
每當(dāng)一個NSOperation執(zhí)行完畢颤难,它就會調(diào)用它的completionBlock屬性一次神年,這提供了一個非常好的方式讓你能在視圖控制器(View Controller)里或者模型(Model)里加入自己更多自己的代碼邏輯。比如說行嗤,你可以在一個網(wǎng)絡(luò)請求操作的completionBlock來處理操作執(zhí)行完以后從服務(wù)器下載下來的數(shù)據(jù)已日。
對于現(xiàn)在Objective-C程序員必須掌握的工具中,NSOperation依然是最基本的一個栅屏。盡管GCD對于內(nèi)嵌異步操作十分理想飘千,NSOperation依舊提供更復(fù)雜、面向?qū)ο蟮挠嬎隳P图惹伲鼘τ谏婕暗礁鞣N類型數(shù)據(jù)占婉、需要重復(fù)處理的任務(wù)又是更加理想的泡嘴。在你的下一個項目里使用它吧甫恩,讓它及帶給用戶歡樂,你自己也會很開心的酌予。