iOS 并發:從 NSOperation 和 Dispatch Queues 開始
- 1. 我們為什么要用并發?
- 2. 關于并發你都需要知道些什么?
- 3. 第一部分:GCD(Grand Central Dispatch)
- 3.1. 什么是隊列
- 3.2. Dispatch Queues
- 3.3. 串行隊列
- 3.4. 并發隊列
- 3.5. 使用隊列 </ol> </li>
- 4. GCD 小抄
- 5. 示例項目
- 5.1. 使用 Concurrent Dispatch Queues
- 5.2. 使用 Serial Dispatch Queues </ol> </li>
- 6. 第二部分:Operation Queues
- 6.1. NSOperation
- 6.2. 取消 operation </ol> </li>
- 7. 接下來看什么? </ol> </div>
- 能更有效的利用 iOS 設備的硬件:現在所有的 iOS 設備都有一個多核處理器,可以讓開發者并行執行多個任務。你應該好好利用這個特性,讓硬件優勢發揮出來。
- 更好的用戶體驗:你可能寫過一些呼叫網絡服務、處理 IO,或者是其他任何執行繁重任務的代碼。你也知道在 UI 所在的線程中做這些操作會把你的 App 凍結住,使它沒任何反應。當用戶遇到這種情況時,他/她會毫不猶豫的直接殺掉或是關閉你的 App。而用并發的話,這些繁重的任務就會被安排到后臺去執行,不會占滿主線程、干擾你用戶的操作。他們依舊能夠點擊按鈕,來回拖動屏幕并在你的 App 中的每個頁面之間跳轉,與此同時在后臺還處理著繁重的裝載任務。
- NSOperation 和 Dispatch Queues 這樣的 API 讓使用并發變得容易:創建并管理線程并不是簡單的事情。這也是為什么很多的開發者一聽到并發,還有多線程代碼這樣的術語時會感到害怕的原因。在 iOS 中我們有強大而易用的并發 API,讓你的生活變得更來福。你無需再為創建線程或管理底層的東西操心,API 會為你搞定。這些 API 的另一個優點是它們能輕松幫你實現同步(synchronization),避免了競態條件(race condition)的產生,而競態條件產生在當多個線程試圖訪問相同的資源的時候,這會引起無法預計的后果。有了同步,你就保護了資源不會被多個線程同時訪問。
- 能確保對一個共享資源進行串行化的訪問,避免了競態條件;
- 任務的執行順序是可預知的;你向一個串行隊列提交任務時,它們被執行的順序與它們被提交的順序相同;
- 你可以創建任意數量的串行隊列;
- DISPATCH_QUEUE_PRIORITY_HIGH
- DISPATCH_QUEUE_PRIORITY_DEFAULT
- DISPATCH_QUEUE_PRIORITY_LOW
- DISPATCH_QUEUE_PRIORITY_BACKGROUND
- 與使用并發隊列的情況相比,下載圖片的時間有些長。原因是我們在同一時刻只下載一張圖片。每個任務必須等到前一個任務執行完成后才會被執行。
- 圖片的下載是按照 image1,image2,image3,和 image4 的順序。因為使用的是每次只能執行一個任務的串行隊列。
- 不遵循 FIFO(先進先出):在 Operation Queues 中,你可以設置 operation(操作)的執行優先級,并且可以在 operation 之間添加依賴,這意味著你可以定義某些 operation,使得它們可以在另外一些 operation 執行完畢之后再被執行。這就是為什么它們不遵循先進先出的順序。
- 默認情況下 Operation Queues 是并發執行:雖然你不能將其改成串行隊列,但還是有一種方法,通過在 operation 之間添加相依性來讓 Operation Queues 中的任務按序執行。
- Operation Queues 是 NSOperationQueue 類的實例,任務被封裝在 NSOperation 的實例中。
- NSBlockOperation - 用這個類來初始化包含一個或多個 blocks 的 operation。該 operation 本身可包含的 block 超過一個,當所有的block 執行完畢后這個 operation 就被視為已完成。
- NSInvocationOperation - 用這個類來初始化一個 operation,能用來調用某指定對象的選擇器(selector)。
- 首先它可以通過
NSOperation
類的 addDependency(op: NSOperation)方法獲得對相依性的支持。如果你有這樣的需求:即某 operation 的啟動需取決于另一個 operation 的執行,那么就得用NSOperation
。
- 其次,你可將 queuePriority 屬性設為以下值來改變執行優先級:
-
你可以取消掉某特定隊列中的某個 operation,或者是取消隊列中所有的 operation。
通過調用NSOperation
類的 cancel() 方法來實現對 operation 的取消。你取消任何 operation 的時候,會是下面三種場景之一:- 你的 operation 已經完成了,這種情況下 cancel 方法沒有任何效果。
- 你的 operation 正在被執行的過程中,這種情況下系統不會強制停止你的 operation 代碼,而是將 cancelled 屬性置為 true。
- 你的 operation 還在隊列中等待被執行,這種情況下你的 operation 就不會被執行。
-
NSOperation
有3個有用的布爾型屬性:finished
,cancelled
和ready
。finished
在 operation 執行完畢后被置為 true。cancelled
在 operation 被取消后被置為 true。ready
在 operation 即將被執行時被置為 true。 -
所有的
NSOperation
在任務被完成后都可以選擇去設置一段 completion block。NSOperation
的finished
屬性變為 true 后這段 block 就會被執行。 - 由于 operation #1 已經開始執行,取消對它沒有任何效果。這就是為什么
cancelled
會被記錄成 false,并且 App 還是會顯示第一張圖片。 - 如果你點擊 Cancel 按鈕足夠快的話,operation #2 會被取消。對 cancelAllOperations() 的調用會停止對該 operation 的執行,所以第二張圖片沒有被下載。
- operation #3 已經排在隊列中,等待 operation #2 的完成。因為 operation #3 是否開始取決于 operation #2 的完成與否,而 operation #2 已經被取消,operation #3 就不會被執行,從隊列中被立即踢出了。
- 沒有對 operation #4 做任何相依性的設置,所以它被并發的執行了,下載了第四張圖片。
作者:hossam ghareeb,原文鏈接,原文日期:2015-12-09
譯者:ray16897188;校對:Channe;定稿:千葉知風并發(Concurrency)在 iOS 開發中總是被看作是洪水猛獸一般。人們以為它是一個很危險的領域,很多開發者都盡量避免與其接觸。更有傳聞說你一定要竭盡所能的避免寫任何關于多線程的代碼。假如你對并發不是很了解卻還去使用它的話,那么我同意:并發是很危險的。只是它的危險是因為你不了解它。試想一下常人一生中體驗過的危險運動和行為有多少,很多對吧?但是當掌握了之后,就會統統變成小菜一碟。并發是把雙刃劍,你應該掌握并學會如何去使用它。它能幫你寫出效率高、執行快、反應靈敏的 App,而與此同時,對它的濫用會無情的毀掉你的 App。這就是為什么在開始寫任何關于并發的代碼之前,先要想一想你為什么要用到并發、需要用到哪個(與并發有關的)API 來解決這個問題。iOS 中我們有很多能用到的 API。在此教程里我會講到最常用的兩個:
NSOperation
和Dispatch Queues
(派發隊列)。我們為什么要用并發?
我知道你是一個有 iOS 背景的出色開發者。然而無論你要做一個什么樣的 App,你都需要了解并發,讓你的 App 更快,更靈敏。我總結了一下學習和使用并發所帶來的優點:
關于并發你都需要知道些什么?
在本篇教程中,我會解釋為理解并發你所需要了解的一切,消除你對它的所有恐懼心理。首先我推薦你去看一下 blocks(即 Swift 中的 closures),它們在并發中會被大量使用。之后我們會聊一下
Dispatch Queues
和NSOperationQueues
。我會帶你了解每個并發中的概念,概念之間的不同,以及如何使用它們。第一部分:GCD(Grand Central Dispatch)
GCD 是在系統的Unix層級中用于管理并發代碼并異步執行操作時最常用的 API。GCD 提供并且管理任務的隊列(queues of tasks)。先來看看什么是隊列。
什么是隊列
隊列是按照先進先出(FIFO)順序管理對象的數據結構。隊列類似于電影院的售票窗口前的長隊。電影票是按先到先得的順序賣出。長隊前面的人先買到票,晚來的人后買到票。計算機科學中的隊列概念和這個很像,因為第一個被加到隊列中的對象也是第一個要從隊列中被移除的。
Dispatch Queues
Dispatch Queues
是一種能夠輕松執行異步和并發任務的方式。它們是隊列,其中的任務是由你的 App 以 blocks(代碼塊)的形式提交。Dispatch Queues
有兩種:(1)串行隊列(serial queues),和(2)并發隊列(concurrent queues)。在講述兩者的不同之前,你需要知道派給這兩種隊列的任務是在另外的線程中被執行,而不是在創建它們的那個線程中被執行。換句話說,你是在主線程中創建block并將其提交到Dispatch Queues
中去。但所有這些任務(block)會在其他的線程中運行,并非主線程。串行隊列
當你選擇創建一個串行隊列時,該隊列在某一時刻只能執行一個任務。該隊列中的所有任務都會彼此尊重,按序執行。然而你無需擔心其他隊列中的任務,意思是你依然可以通過使用多個串行隊列來以并發的形式執行任務。例如你可以創建兩個串行隊列,每一個隊列某一時刻只能執行一個任務,但是還是有最多兩個任務被并發執行。
用串行隊列來管理一個共享資源(shared resource)再合適不過。它提供的對共享資源的訪問確保是串行化的,從而防止競態條件的發生。想象一下有個售票小攤,還有一大堆人想買電影票,那小攤的售票員就是一個共享資源。如果這個售票員必須同時為這堆人服務時就會特別混亂。為避免這個情況,買票的人會被要求去排隊(串行隊列),這樣售票員同一時刻就可以只對一人服務。
再說一遍,這里沒有說電影院每時刻只能為一個顧客服務。如果電影院再開兩個售票點,就可以同時服務三位客戶了。這也是為什么我說過即使你使用串行隊列還依然能并行執行多個任務的原因。
使用串行隊列的優點:
并發隊列
正如其名,并發隊列可以讓你并行的執行多個任務。任務(block)按照它們被加入到隊列中的順序依次開始,但是它們都是并發的被執行,并不需要彼此等待才開始。并發隊列能保證任務按同一順序開始,但你不能知道執行的順序、執行的時間以及在某一時刻正在被執行任務的數量。
比如你向一個并發隊列提交了三個任務(任務#1,#2和#3)。任務被并發執行,按照加入隊列的順序依次開始。然而任務的執行時間和結束時間都不相同。即使任務#2和#3可能會遲一些開始,它們可能都會先于任務#1結束。對任務的執行是由系統本身決定。
使用隊列
已經解釋了串行隊列和并發隊列,現在來看看如何使用它們。系統會缺省為每個應用提供一個串行隊列和四個并發隊列。其中 main dispatch queue(主派發隊列)是全局可用的串行隊列,在應用的主線程中執行任務。這個隊列被用來更新 App 的 UI,執行所有與更新 UIViews 相關的任務。該隊列中同一時刻只執行一個任務,這就是為什么當你在主隊列中運行一個繁重的任務時UI會被阻塞的原因。
除主隊列之外,系統還提供了4個并發隊列。我們管它們叫 Global Dispatch queues(全局派發隊列)。這些隊列對整個應用來說是全局可用的,彼此只有優先級高低的區別。要使用其中一個全局并發隊列的話,你得使用 dispatch_get_global_queue 函數獲得一個你想要的隊列的引用,該函數的第一個參數取如下值:
這些隊列類型代表著執行優先級。帶有 HIGH 的隊列有最高優先級,BACKGROUND 則是最低的優先級。這樣你就能基于任務的優先級來決定要用哪一個隊列。還要注意這些隊列也被 Apple 的 API 所使用,所以這些隊列中并不只有你自己的任務。
最后,你可以創建任何數量的串行或并發隊列。使用并發隊列的情況下,即使你可以自己創建,我還是強烈建議你使用上面那四個全局隊列。
GCD 小抄
現在你應該有了一個對
Dispatch Queues
的基本了解。我會給你一個簡單的小抄做參考。里面很簡單,包含了對 GCD 你需要了解的所有信息。還不錯吧?現在我們來研究一個簡單的示范,看看如何使用
Dispatch Queues
。我會告訴你如何使用Dispatch Queues
來優化 App 的性能,讓它有更快的響應速度。示例項目
我們的初始項目很簡單,它展示4個 image views,每個 image view 顯示一張來自遠端站點的圖片。圖片的請求是在主線程中完成。為了給你展示這么做對UI響應會有何影響,我還在圖片下面加了一個簡單的 slider。下載并運行這個初始項目。點擊 Start 按鈕開始圖片的下載,然后在圖片下載的過程中拖動 slider,你會發現根本就拖不動。
你點了 Start 按鈕之后,圖片就會在主線程中開始下載。顯然這種方式糟糕至極,讓 UI 無法響應。不幸的是時至今日還有很對的 App 依舊在主線程中執行繁重的裝載任務。現在我們使用Dispatch Queues
來解決這個問題。首先我們使用并發隊列的解決方案,隨后再使用串行隊列的解決方案。
使用 Concurrent Dispatch Queues
現在回到 Xcode 項目的 ViewController.swift 文件中。如果你細看一下代碼,就會看到點擊事件的方法 didClickOnStart。這個方法負責處理圖片的下載。我們現在是這樣來完成該任務的:
@IBAction func didClickOnStart(sender: AnyObject) { let img1 = Downloader.downloadImageWithURL(imageURLs[0]) self.imageView1.image = img1 let img2 = Downloader.downloadImageWithURL(imageURLs[1]) self.imageView2.image = img2 let img3 = Downloader.downloadImageWithURL(imageURLs[2]) self.imageView3.image = img3 let img4 = Downloader.downloadImageWithURL(imageURLs[3]) self.imageView4.image = img4 }
每一個 downloader 都被看作是一個任務,而所有的任務都在主隊列中被執行。現在我們來獲得一個全局并發隊列的引用,該隊列是默認優先級的那個。
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) dispatch_async(queue) { () -> Void in let img1 = Downloader.downloadImageWithURL(imageURLs[0]) dispatch_async(dispatch_get_main_queue(), { self.imageView1.image = img1 }) }
先用 dispatch_get_global_queue 獲得到默認并發隊列的引用,然后在 block 中提交一個任務,下載第一張圖片。當圖片下載完成后,我們再向主隊列提交另外一個任務,這個任務用拿下載好了的圖片去更新 image view。換句話說,我們就是將圖片下載任務放到了后臺線程中執行,而 UI 相關的任務則是在主線程中執行。
對剩下的圖片做同樣改動,代碼如下:
@IBAction func didClickOnStart(sender: AnyObject) { let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) dispatch_async(queue) { () -> Void in let img1 = Downloader.downloadImageWithURL(imageURLs[0]) dispatch_async(dispatch_get_main_queue(), { self.imageView1.image = img1 }) } dispatch_async(queue) { () -> Void in let img2 = Downloader.downloadImageWithURL(imageURLs[1]) dispatch_async(dispatch_get_main_queue(), { self.imageView2.image = img2 }) } dispatch_async(queue) { () -> Void in let img3 = Downloader.downloadImageWithURL(imageURLs[2]) dispatch_async(dispatch_get_main_queue(), { self.imageView3.image = img3 }) } dispatch_async(queue) { () -> Void in let img4 = Downloader.downloadImageWithURL(imageURLs[3]) dispatch_async(dispatch_get_main_queue(), { self.imageView4.image = img4 }) } }
你向默認隊列以并發任務的形式提交了四個圖片的下載任務。現在創建項目然后運行 App ,運行起來應該更快了(如果你收到任何錯誤告警,在把你的代碼和上面的比較一下)。注意到下載圖片的過程中你應該可以拖動那個 slider,沒有任何延遲。
使用 Serial Dispatch Queues
另一種解決延遲問題的方法是使用串行隊列。現在還是回到 ViewController.swift 中的 didClickOnStart() 方法。這回我們用一個串行隊列來下載圖片。使用串行隊列時你一定要留意你所引用的到底是哪一個串行隊列。每一個 App 都有一個默認的串行隊列,實際上它也是UI任務相關的主隊列。所以切記用串行隊列的時候,你一定要創建一個新的,否則就會在 App 嘗試執行更新UI相關任務的同時又執行你的任務。這就會產生錯誤,引起延時,毀掉用戶體驗。你可以使用 dispatch_queue_create 函數創建一個新的隊列,然后將所有任務按相同方式提交給它,和我們之前做的一樣。更改之后,代碼如下:
@IBAction func didClickOnStart(sender: AnyObject) { let serialQueue = dispatch_queue_create("com.appcoda.imagesQueue", DISPATCH_QUEUE_SERIAL) dispatch_async(serialQueue) { () -> Void in let img1 = Downloader .downloadImageWithURL(imageURLs[0]) dispatch_async(dispatch_get_main_queue(), { self.imageView1.image = img1 }) } dispatch_async(serialQueue) { () -> Void in let img2 = Downloader.downloadImageWithURL(imageURLs[1]) dispatch_async(dispatch_get_main_queue(), { self.imageView2.image = img2 }) } dispatch_async(serialQueue) { () -> Void in let img3 = Downloader.downloadImageWithURL(imageURLs[2]) dispatch_async(dispatch_get_main_queue(), { self.imageView3.image = img3 }) } dispatch_async(serialQueue) { () -> Void in let img4 = Downloader.downloadImageWithURL(imageURLs[3]) dispatch_async(dispatch_get_main_queue(), { self.imageView4.image = img4 }) } }
正如我們所見,與并行隊列解決方案唯一的不同就是需要創建一個串行隊列。再次點擊 build 然后運行 App ,你又會看見圖片在后臺進行下載,所以可以和UI進行交互。
但是你會注意到兩點:
第二部分:Operation Queues
GCD 是一個底層的 C API,能讓開發者并行執行任務。與之相對比,Operation queues 是對隊列模型的高層級抽象,而且是基于GCD創建的。這意味著你可以像GCD那樣執行并發任務,只不過是以一種面性對象的風格。簡而言之,Operation Queues 讓開發者的“來福”更進一步。
與 GCD 不同的是,Operation Queues 不遵循先進先出的順序。以下是 Operation Queues 和
Dispatch Queues
的不同:NSOperation
任務是以 NSOperation 實例的形式被提交到 Operation Queues 中去的。之前說過 GCD 中任務是以 block 的形式被提交。在這里也是類似,只不過是需要被綁到 NSOperation 實例中。你可以簡單的將
NSOperation
看作是一套工作任務的整體。NSOperation
是一個抽象的類,不可以被直接拿來用,所以你只能使用NSOperation
的子類。在 iOS 的 SDK 中有兩個NSOperation
的具體子類。這兩個類可以直接用,但是你也可以用NSOperation
的子類,創建你自己的類來完成特定 operation。這兩個可以直接使用的類是:那么
NSOperation
的優勢在哪里?public enum NSOperationQueuePriority : Int { case VeryLow case Low case Normal case High case VeryHigh}
擁有最高優先級的 operation 會被第一個執行。
現在來重寫一下我們的示例項目,這次使用 NSOperationQueues。首先在 ViewController 類中聲明如下變量:
var queue = NSOperationQueue()
然后將 didClickOnStart 方法中的代碼替換成下面的,再看看在 NSOperationQueue 中怎樣去執行 operation:
@IBAction func didClickOnStart(sender: AnyObject) { queue = NSOperationQueue() queue.addOperationWithBlock { () -> Void in let img1 = Downloader.downloadImageWithURL(imageURLs[0]) NSOperationQueue.mainQueue().addOperationWithBlock({ self.imageView1.image = img1 }) } queue.addOperationWithBlock { () -> Void in let img2 = Downloader.downloadImageWithURL(imageURLs[1]) NSOperationQueue.mainQueue().addOperationWithBlock({ self.imageView2.image = img2 }) } queue.addOperationWithBlock { () -> Void in let img3 = Downloader.downloadImageWithURL(imageURLs[2]) NSOperationQueue.mainQueue().addOperationWithBlock({ self.imageView3.image = img3 }) } queue.addOperationWithBlock { () -> Void in let img4 = Downloader.downloadImageWithURL(imageURLs[3]) NSOperationQueue.mainQueue().addOperationWithBlock({ self.imageView4.image = img4 }) }}
如上所見,你使用了 addOperationWithBlock 方法來創建一個新的、帶有某給定 block(或者它在 Swift 中的名字:閉包)的 operation。很簡單,對吧?為在主隊列中完成某個任務,與使用 GCD 時調用 dispatch_async() 不同,我們用 NSOperationQueue(NSOperationQueue.mainQueue())也可以達到相同結果,將你想要在主隊列中執行的 operation 提交過去。
可以運行一下這個 App 做個快速測試。如果代碼輸入正確的話, App 應該能夠在后臺下載圖片,不會阻塞UI。
之前的例子中我們使用了 addOperationWithBlock 方法把 operation 添加到隊列中。再讓我們來看看如何使用 NSBlockOperation:在達到相同的效果的同時,還會給我們提供更多的功能和選項,比如設置 completion handler。改后的 didClickOnStart 方法如下:
@IBAction func didClickOnStart(sender: AnyObject) { queue = NSOperationQueue() let operation1 = NSBlockOperation(block: { let img1 = Downloader.downloadImageWithURL(imageURLs[0]) NSOperationQueue.mainQueue().addOperationWithBlock({ self.imageView1.image = img1 }) }) operation1.completionBlock = { print("Operation 1 completed") } queue.addOperation(operation1) let operation2 = NSBlockOperation(block: { let img2 = Downloader.downloadImageWithURL(imageURLs[1]) NSOperationQueue.mainQueue().addOperationWithBlock({ self.imageView2.image = img2 }) }) operation2.completionBlock = { print("Operation 2 completed") } queue.addOperation(operation2) let operation3 = NSBlockOperation(block: { let img3 = Downloader.downloadImageWithURL(imageURLs[2]) NSOperationQueue.mainQueue().addOperationWithBlock({ self.imageView3.image = img3 }) }) operation3.completionBlock = { print("Operation 3 completed") } queue.addOperation(operation3) let operation4 = NSBlockOperation(block: { let img4 = Downloader.downloadImageWithURL(imageURLs[3]) NSOperationQueue.mainQueue().addOperationWithBlock({ self.imageView4.image = img4 }) }) operation4.completionBlock = { print("Operation 4 completed") } queue.addOperation(operation4)}
對每個 operation,我們都為其創建了一個新的 NSBlockOperation 實例并將任務封裝在一個 block 中。而使用了 NSBlockOperation,你還可以設置 completion handler。當 operation 完成后,completion handler 就會被調用。將示例運行一下,就會在控制臺看見這樣的輸出:
Operation 1 completedOperation 3 completedOperation 2 completedOperation 4 completed
取消 operation
之前提過,NSBlockOperation 能夠讓你管理 operation。那么現在來看看如何取消一個 operation。首先給 navigation bar 加一個 bar button item,將其命名為 Cancel。為展示取消 operation,我們在 Operation #2 和 Operation #1 之間添加一個相依性,Operation #3 和 Operation #2 之間添加另一個相依性。也就是說 Operation #2 會在 Operation #1 完成后開始執行,而 Operation #3 會在 Operation #2 完成后執行。Operation #4 并沒有相依性,它會被并發執行。要取消 operation 的話,你只需調用 NSOperationQueue 的 cancelAllOperations() 方法。在ViewController 類中插入下面的方法:
@IBAction func didClickOnCancel(sender: AnyObject) { self.queue.cancelAllOperations()}
記住需要把你在 navigation bar 上添加的 Cancel 按鈕與 didClickOnCancel 方法關聯起來。你可以這么做:返回 Main.storyboard 文件,打開Connections Inspector,這里你會在Received Actions區域中看見unlink didSelectCancel()。點擊 + 并將其從空圓圈拖拽到 Cancel bar button 上。然后在 didClickOnStart 方法中添加相依性:
operation2.addDependency(operation1)operation3.addDependency(operation2)
接下來把 operation #1 的 completion block 改一下,讓它在控制臺打印出 cancel 的狀態:
operation1.completionBlock = { print("Operation 1 completed, cancelled:\(operation1.cancelled) ")}
你可以自己改一下 operation #2,#3 和 #4 的打印語句,這樣可以更好的理解這一過程。然后創建并運行項目。你點擊了 Start 按鈕之后,再按 Cancel 按鈕,這就會在 operation #1 執行完畢后取消所有的 operation。下面告訴了我們都發生了些什么:
接下來看什么?
本篇教程中我為你講解了 iOS 中并發的概念,以及你在 iOS 中該如何去使用它。我給了你一個還不錯的并發入門簡介,解釋了 GCD,并示范了怎樣去創建串行和并發隊列。除此之外,我們還看了一下 NSOperationQueues。你現在應該對 GCD 和 NSOperationQueues 之間的不同有所了解了。
如果想進一步了解 iOS 的并發,建議你去看一下 Apple 的并發指南。
你可以從 iOS Concurrency repository on Github 這里找到此教程提到的全套源代碼以作參考。
隨便問任何問題,我真心喜歡你的評論。
本文由 SwiftGG 翻譯組翻譯,已經獲得作者翻譯授權,最新文章請訪問 http://swift.gg。
來自: http://swift.gg/2016/01/08/ios-concurrency-getting-started-with-nsoperation-and-dispatch-queues/