這篇主要總結下iOS開發中多線程的使用,多線程開發一般使用NSThread、NSOperation及GCD三種方式,常用GCD及NSOperation。
創建線程主要有以下三種方式
需要注意的是對于多個線程可能同時訪問一個對象的時候,使用“@synchronized”來解決這類線程同步問題。
在子線程中通知主線程通常使用以下兩種辦法:
NSOperation有三種使用方式,分別是NSInvocationOperation、NSBlockOperation以及自定義NSOperation操作,并可對NSOperation設置依賴關系,進而確定任務執行的先后順序,還可以對任務的狀態進行監控甚至控制,以及設置線程最大并發數量等等。
(1)NSInvocationOperation
首先是NSInvocationOperation方式創建線程如圖所示,需要注意的是這種方式創建的操作只有加入到隊列去執行才是異步操作,否則還是在主線程同步執行
加入到隊列自動執行時,會新建線程異步執行
(2)NSBlockOperation
第二種則是使用NSBlockOperation,同樣需要注意的是當操作的任務數只有一個時,任務會在當前線程同步執行
當任務數大于1的時候,會開啟新線程并異步執行
當把NSBlockOperation定義的操作加入到隊列中時,會以異步并發的方式去執行這些任務
(3)繼承NSOperation,自定義Operation
這種方法較為靈活,通過繼承NSOperation并重寫相關方法實現,例如SDWebImage就用到了這種方式。
(4)設置依賴
如果任務之間有先后順序依賴,可以對他們設置依賴關系解決這個問題,如圖所示,operation1依賴operation2,而operation2又依賴于operation3,于是執行順序為operation3、operation2、operation1
(5)設置任務最大并發數
可以通過設置maxConcurrentOperationCount限定任務并發數量,避免并發操作消耗太多資源
(6)任務狀態的監控以及設置
可以獲取到任務的執行狀態,是否執行中還是取消了或者完成了等等
需要注意的是,發送取消任務的消息,任務并不一定就真的取消,因為加入到隊列以后,任務的執行都是由系統來管理了,取消成功的前提是任務還沒有開始執行,即使該任務成功取消了,也還是會被系統認定為任務已經完成finished,所以如果有其他任務依賴于已經被取消的任務,需要用“isCancelled”進行判斷,尤其是任務完成回調事件里做一些操作的話,可能說的有點繞,詳細見下圖:
如果不進行判斷,即使operation3已經取消了,由于系統認為取消的任務也算finished,所以operation3的任務完成回調事件仍然觸發
更詳細的可以參考Concurrency PRogramming Guide中這部分的內容
當然,還可以直接對整個列進行管理,包括掛起或恢復隊列中所有任務,取消隊列里所有任務等等
GCD的使用主要有以下幾種方式:
(1)在主線程中添加任務,dispatch_async異步方式執行,常見使用場景是進入以后,異步加載相關圖片信息
(2)GCD中解決線程同步的問題可以使用串行隊列,串行隊列里任務會按照添加順序依次執行,需要注意的是以distpatch_sync同步方式執行任務,所有任務都是在主線程進行的
(3)在串行隊列中以dispatch_async異步方式執行任務,則系統開啟一個新線程執行任務
(4)在并發隊列中,以dispatch_async異步方式執行任務,則系統會根據任務數量建立一定數量的線程來執行任務,注意這里用的是全局并發隊列。
(5)GCD方式執行延時任務
上圖為回到主線程執行延時任務,下圖為開啟新的線程執行延時任務
(6)隊列組
當需要同時執行多個任務,例如同時下載多張圖片,并對圖片進行處理顯示這樣類似的應用場景時,可以通過隊列組的方式并發執行任務,提高效率,使用方式如圖
(7)解決線程同步的問題除了使用串行隊列外,還可以使用信號量來解決,詳細參考Concurrency Programming Guide,另外需要注意的是以下兩個使用方式會產生問題
一個是在主線程以dispatch_sync同步方式執行任務會死鎖
另一個是在并行隊列中以dispatch_sync同步方式執行任務,會失去并發的意義,最終所有任務都還是在主線程中一個一個執行
一般情況用NSOperation和GCD可以滿足應用需求,GCD方式使用起來已經足夠簡潔,而NSOperation使用起來則更加靈活方便,可以監聽任務執行狀態,取消任務,設置任務最大并發數量等等。
新聞熱點
疑難解答