為什么要寫這個系列,因為百度了一下,找了很多都是些片面的Blog,拷貝來拷貝去的,寫的也很粗糙。所以,我要寫這個系列,盡量把官網(wǎng)文檔中GCD的強(qiáng)大功能完整的表達(dá)出來。方便自己,也方便別人,如果發(fā)現(xiàn)有問題,歡迎提出本教程的計劃:在完整的看過GCD的官方文檔之后,我實在想不出來如何用一篇文章詳細(xì)完整的寫出來如此多的功能。所以,決定開一個專欄來寫這個教程。計劃8篇文章,分別介紹各種功能,每種功能會附上簡單完整的示例代碼。最后的一篇文章會進(jìn)行總結(jié),總結(jié)出GCD的經(jīng)典使用場景。源代碼只提供Swift版本。因為要上班,計劃一個月內(nèi)完成。每周兩篇。原創(chuàng)Blog,轉(zhuǎn)載請注明出處這個專欄地址http://blog.csdn.net/column/details/swift-gcd.htmlGCD全稱:Grand Central Dispatch 簡介:GCD是對多線程、多核開發(fā)較完整的封裝。在使用GCD的時候,系統(tǒng)會自動根據(jù)CPU使用情況進(jìn)行調(diào)度,所以GCD是一個簡單易用,但是效果很好地多線程多核開發(fā)工具。要注意的地方:1、慎用fork()函數(shù)(不是十分清楚流程不要用)2、GCD是C語言級別的API,所以不會抓到異常,在一個提交到GCD的任務(wù)完成之前,應(yīng)當(dāng)處理完異常。教程一教程一涵蓋了1、GCD全局隊列的四個優(yōu)先級2、幾種本文使用到的GCD類型3、dispatch_async/dispatch_async_f4、dispatch_sync/dispatch_sync_f一、概念與類型對于GCD來說,所有的執(zhí)行都放到隊列中(queue),隊列的特點是FIFO(先提交的先執(zhí)行)。GCD的隊列分為幾種,主隊列(main),全局隊列(global),用戶創(chuàng)建隊列(create)對于全局隊列,默認(rèn)有四個,分為四個優(yōu)先級[cpp] view plaincopy#define DISPATCH_QUEUE_PRIORITY_HIGH? ? ? ? 2? #define DISPATCH_QUEUE_PRIORITY_DEFAULT? ? ? 0? #define DISPATCH_QUEUE_PRIORITY_LOW? ? ? ? ? (-2)? #define DISPATCH_QUEUE_PRIORITY_BACKGROUND? INT16_MIN? DISPATCH_QUEUE_PRIORITY_HIGH :優(yōu)先級最高,在default,和low之前執(zhí)行DISPATCH_QUEUE_PRIORITY_DEFAULT 默認(rèn)優(yōu)先級,在low之前,在high之后DISPATCH_QUEUE_PRIORITY_LOW 在high和default后執(zhí)行DISPATCH_QUEUE_PRIORITY_BACKGROUND:提交到這個隊列的任務(wù)會在high優(yōu)先級的任務(wù)和已經(jīng)提交到background隊列的執(zhí)行完后執(zhí)行。官方文檔:(the queue is scheduled for execution after all high priority queues have been scheduled and the system runs items on a thread whose priority is set for background status.)幾種使用到的類型[cpp] view plaincopytypealias dispatch_queue_t = NSObject //輕量級的用來描述執(zhí)行任務(wù)的隊列? typealias dispatch_block_t = () -> Void //隊列執(zhí)行的閉包(Objective C中的block)? 幾個概念異步 提交的任務(wù)立刻返回,在后臺隊列中執(zhí)行同步 提交的任務(wù)在執(zhí)行完成后才會返回并行執(zhí)行(全局隊列) 提交到一個隊列的任務(wù),比如提交了任務(wù)1和任務(wù)2,在任務(wù)1開始執(zhí)行,并且沒有執(zhí)行完畢時候,任務(wù)2就可以開始執(zhí)行。串行執(zhí)行(用戶創(chuàng)建隊列) 提交到一個隊列中的任務(wù),比如提交了任務(wù)1和任務(wù)2,只有任務(wù)1結(jié)束后,任務(wù)2才可執(zhí)行注意:提交到隊列中的任務(wù)是串行執(zhí)行,還是并行執(zhí)行由隊列本身決定。二、示例詳解[plain] view plaincopyfunc dispatch_async(_ queue: dispatch_queue_t!,? ? ? ? ? ? ? ? ? ? _ block: dispatch_block_t!)? 參數(shù):queue 提交到的隊列,隊列的類型決定了是串行還是并行執(zhí)行隊列中的任務(wù)block 執(zhí)行的閉包[plain] view plaincopyfunc dispatch_async_f(_ queue: dispatch_queue_t!,? ? ? ? ? ? ? ? ? ? ? _ context: UnsafeMutablePointer,? ? ? ? ? ? ? ? ? ? ? _ work: dispatch_function_t)? 參數(shù)queue 提交到的隊列,隊列的類型決定了是串行還是并行執(zhí)行隊列中的任務(wù)context 傳遞給work的參數(shù)work 執(zhí)行的函數(shù)(C語言函數(shù))dispatch_sync 和 dispatch_sync的參數(shù)和上述對應(yīng)一致,所以不再列出總得來說帶有后綴_f(比如dispatch_sync_f,dispatch_after_f)就是提交給隊列一個C語言函數(shù),因為極少用到這種形式,這里僅給出一個簡單例子,后面的涉及到_f的都略過。1、dispatch_async/dispatch_sync功能:提交到隊列中異步/同步執(zhí)行本示例:下載一張圖片,圖片下載完畢后通知UI改變注意:要改變UI必須在主隊列上執(zhí)行這里用到了一個獲取全局隊列的函數(shù)[plain] view plaincopyfunc dispatch_get_global_queue(_ identifier: Int,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? _ flags: UInt) -> dispatch_queue_t!? 這個函數(shù)的第一個參數(shù)是隊列的優(yōu)先級,第二個參數(shù)尚沒有意義,直接寫0就可以了。創(chuàng)建一個基于單頁面的Swift工程,然后在ViewController.swift中,[plain] view plaincopyclass ViewController: UIViewController{? ? ? ? var imageview = UIImageView(frame: CGRectMake(40,40,200,200))? ? ? ? override func viewDidLoad(){? ? ? ? ? ? super.viewDidLoad()? ? ? ? ? ? imageview.contentMode = UIViewContentMode.ScaleAspectFit? ? ? ? ? ? self.view.addSubview(imageview)? ? ? ? ? ? let url = "http://f.hiphotos.baidu.com/image/pic/item/e1fe9925bc315c60191d32308fb1cb1348547760.jpg"? ? ? ? ? ? let imageURL = NSURL(string:url)? ? ? ? var globalQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)? ? ? dispatch_async(globalQueueDefault){? ? ? ? ? var imageData = NSData(contentsOfURL:imageURL!)? ? ? ? ? var image = UIImage(data:imageData!)? ? ? ? ? if let successfulImage = image{? ? ? ? ? ? ? sleep(2)? ? ? ? ? ? ? dispatch_async(dispatch_get_main_queue()){? ? ? ? ? ? ? ? ? self.imageview.image = successfulImage? ? ? ? ? ? ? }? ? ? ? ? }? ? ? }? ? ? }? ? ? ? override func didReceiveMemoryWarning(){? ? ? ? ? ? super.didReceiveMemoryWarning()? ? ? ? }? ? }? ? 執(zhí)行,觀察下效果:view立刻載入,然后過一段時間,圖片下載完了,UI改變?nèi)缓螅覀冇^察dispatch_sync只需要修改這一行即可[plain] view plaincopydispatch_sync(globalQueueDefault,0){? 執(zhí)行,觀察下效果:view載入很慢,但是在載入的時候,圖片下載完了。UI已經(jīng)改變??梢源蛟谶@一行打斷點,會發(fā)現(xiàn)異步執(zhí)行會立刻返回,同步執(zhí)行會等待執(zhí)行結(jié)束后返回。所以,當(dāng)我們有一件非常耗時的事情,放到后臺隊列中去做,等做完了通知UI改變,是不會阻塞UI,降低用戶體驗的。2、dispatch_async_f/dispatch_sync_f簡單的實例,把一個C函數(shù)提交給隊列首先,建立一個基于單頁面的swift工程,命名為testForCSDN,然后再新建一個C語言文件,命名為hwcText->點擊包括頭文件->點擊包含Bridging-Header.h這樣,工程里多了三個文件hwcTest.chwcTest.htestForCSDN-Bridging-Header.h附上完整的代碼testForCSDN-Bridging-Header.h[cpp] view plaincopy#import "hwcTest.h"? hwcTest.h[cpp] view plaincopy#include#includetypedef void (*hwcTestForGCD)(void*);? hwcTestForGCD getFuncPointer();? hwcTest.c[cpp] view plaincopy#include "hwcTest.h"? void realFunction(void *input){? ? ? for(int i = 0;i < 5;i++){? ? ? ? ? printf("%d\n",i);? ? ? ? ? sleep(1);? ? ? }? }? hwcTestForGCD getFuncPointer(){? ? ? return realFunction;? }? ViewController.swift[plain] view plaincopyclass ViewController: UIViewController{? ? ? ? var imageview = UIImageView(frame: CGRectMake(40,40,200,200))? ? ? ? override func viewDidLoad(){? ? ? ? ? ? super.viewDidLoad()? ? ? ? ? ? var globalQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)? ? ? dispatch_async_f(globalQueueDefault,nil,getFuncPointer())? ? ? println("dispatch is over")? ? ? }? ? ? ? override func didReceiveMemoryWarning(){? ? ? ? ? ? super.didReceiveMemoryWarning()? ? ? ? }? ? }? 然后執(zhí)行,會發(fā)現(xiàn)輸出[plain] view plaincopy0? dispatch is over? 1? 2? 3? 4? 然后,我們同樣改成dispatch_sync后執(zhí)行,發(fā)現(xiàn)輸出[plain] view plaincopy0? 1? 2? 3? 4? 5? dispatch is over? 這里更能體會到了,什么是同步,什么是異步了吧。三、理解下并行隊列和串行隊列使用一或者二中的工程都可以,修改ViewController.swft中的代碼就可以這里用到了一個函數(shù)[plain] view plaincopyfunc dispatch_queue_create(_ label: UnsafePointer,
_ attr: dispatch_queue_attr_t!) -> dispatch_queue_t!
參數(shù)
label String類型的隊列標(biāo)示符,通常取做com.companyname.productname.functionname
attr? ? 兩種類型。DISPATCH_QUEUE_SERIAL創(chuàng)建一個順序執(zhí)行隊列, DISPATCH_QUEUE_CONCURRENT創(chuàng)建同時執(zhí)行隊列
ViewController的完整代碼,這里提交兩個任務(wù),通過輸出來判斷是并行隊列,還是串行隊列
[plain] view plaincopy
class ViewController: UIViewController{
var imageview = UIImageView(frame: CGRectMake(40,40,200,200))
override func viewDidLoad(){
super.viewDidLoad()
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)){
for var i = 0;i < 5;i++ {
NSLog("First task:%d",i)
sleep(1)
}
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)){
for var j = 0;j < 5;j++ {
NSLog("Second task:%d",j)
sleep(1)
}
}
println("dispatch is over")
}
override func didReceiveMemoryWarning(){
super.didReceiveMemoryWarning()
}
}
這里執(zhí)行輸出為:
[plain] view plaincopy
First task:0
Second task:0
First task:1
Second task:1
First task:2
Second task:2
First task:3
Second task:3
First task:4
Second task:4
這段代碼執(zhí)行時間4.03s
然后,我們使用串行執(zhí)行的隊列
[plain] view plaincopy
class ViewController: UIViewController{
var imageview = UIImageView(frame: CGRectMake(40,40,200,200))
override func viewDidLoad(){
super.viewDidLoad()
var serialQueue =? dispatch_queue_create(label:
"com.test.helloHwc",attr:DISPATCH_QUEUE_SERIAL)
dispatch_async(serialQueue){
for var i = 0;i < 5;i++ {
NSLog("First task:%d",i)
sleep(1)
}
}
dispatch_async(serialQueue){
for var j = 0;j < 5;j++ {
NSLog("Second task:%d",j)
sleep(1)
}
}
println("dispatch is over")
}
override func didReceiveMemoryWarning(){
super.didReceiveMemoryWarning()
}
}
這里輸出為
[plain] view plaincopy
First task:0
First task:1
First task:2
First task:3
First task:4
Second task:0
Second task:1
Second task:2
Second task:3
Second task:4
這段代碼執(zhí)行時間8.06秒
看出來并行和串行執(zhí)行的差別了吧。
所以,記住一點,把過程不相關(guān)的任務(wù),提交到并行的隊列中會顯著提高效率