完整詳解 swift GCD系列(一)dispatch_async;dispatch_sync;dispatch_async_f;dispatch_sync_f
阿新 • • 發佈:2019-01-15
為什麼要寫這個系列,因為百度了一下,找了很多都是些片面的Blog,拷貝來拷貝去的,寫的也很粗糙。
所以,決定開一個專欄來寫這個教程。計劃8篇文章,分別介紹各種功能,每種功能會附上簡單完整的示例程式碼。最後
GCD
全稱:Grand Central Dispatch
簡介:GCD是對多執行緒、多核開發較完整的封裝。在使用GCD的時候,系統會自動根據CPU使用情況進行排程,所以GCD是
一個簡單易用,但是效果很好地多執行緒多核開發工具。
要注意的地方:
1、慎用fork()函式(不是十分清楚流程不要用)
2、GCD是C語言級別的API,所以不會抓到異常,在一個提交到GCD的任務完成之前,應當處理完異常。
教程一
教程一涵蓋了
1、GCD全域性佇列的四個優先順序
2、幾種本文使用到的GCD型別
3、dispatch_async/dispatch_async_f
4、dispatch_sync/dispatch_sync_f
一、概念與型別
對於GCD來說,所有的執行都放到佇列中(queue),佇列的特點是FIFO(先提交的先執行)。
GCD的佇列分為幾種,主佇列(main),全域性佇列(global),使用者建立佇列(create)
對於全域性佇列,預設有四個,分為四個優先順序
DISPATCH_QUEUE_PRIORITY_HIGH:優先順序最高,在default,和low之前執行
DISPATCH_QUEUE_PRIORITY_DEFAULT 預設優先順序,在low之前,在high之後
DISPATCH_QUEUE_PRIORITY_LOW 在high和default後執行
DISPATCH_QUEUE_PRIORITY_BACKGROUND:提交到這個佇列的任務會在high優先順序的任務和已經提交到background佇列的執行完後執行。官方文件:(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.)
幾種使用到的型別
幾個概念
非同步提交的任務立刻返回,在後臺佇列中執行
同步提交的任務在執行完成後才會返回
並行執行(全域性佇列)提交到一個佇列的任務,比如提交了任務1和任務2,在任務1開始執行,並且沒有執行完畢時候,任務2就可以開始執行。
序列執行(使用者建立佇列) 提交到一個佇列中的任務,比如提交了任務1和任務2,只有任務1結束後,任務2才可執行
注意:提交到佇列中的任務是序列執行,還是並行執行由佇列本身決定。
二、示例詳解
queue 提交到的佇列,佇列的型別決定了是序列還是並行執行佇列中的任務
block 執行的閉包
queue 提交到的佇列,佇列的型別決定了是序列還是並行執行佇列中的任務
context 傳遞給work的引數
1、dispatch_async/dispatch_sync
功能:提交到佇列中非同步/同步執行
本示例:下載一張圖片,圖片下載完畢後通知UI改變
注意:要改變UI必須在主佇列上執行
這裡用到了一個獲取全域性佇列的函式
建立一個基於單頁面的Swift工程,然後在ViewController.swift中,
然後,我們觀察dispatch_sync
只需要修改這一行即可
執行,觀察下效果:view載入很慢,但是在載入的時候,圖片下載完了。UI已經改變。可以打在這一行打斷點,會發現非同步執行會立刻返回,同步執行會等待執行結束後返回。
所以,當我們有一件非常耗時的事情,放到後臺佇列中去做,等做完了通知UI改變,是不會阻塞UI,降低使用者體驗的。
2、dispatch_async_f/dispatch_sync_f
簡單的例項,把一個C函式提交給佇列
首先,建立一個基於單頁面的swift工程,命名為testForCSDN,然後再新建一個C語言檔案,命名為hwcText->點選包括標頭檔案->點選包含Bridging-Header.h
這樣,工程裡多了三個檔案
hwcTest.c
hwcTest.h
testForCSDN-Bridging-Header.h
附上完整的程式碼
testForCSDN-Bridging-Header.h
hwcTest.h
hwcTest.c
然後,我們同樣改成dispatch_sync後執行,發現輸出
三、理解下並行佇列和序列佇列
使用一或者二中的工程都可以,修改ViewController.swft中的程式碼就可以
這裡用到了一個函式
label String型別的佇列標示符,通常取做com.companyname.productname.functionname
attr 兩種型別。DISPATCH_QUEUE_SERIAL建立一個順序執行佇列, DISPATCH_QUEUE_CONCURRENT建立同時執行佇列
ViewController的完整程式碼,這裡提交兩個任務,通過輸出來判斷是並行佇列,還是序列佇列
所以,我要寫這個系列,儘量把官網文件中GCD的強大功能完整的表達出來。方便自己,也方便別人,如果發現有問題,歡迎提出
本教程的計劃:在完整的看過GCD的官方文件之後,我實在想不出來如何用一篇文章詳細完整的寫出來如此多的功能。所以,決定開一個專欄來寫這個教程。計劃8篇文章,分別介紹各種功能,每種功能會附上簡單完整的示例程式碼。最後
的一篇文章會進行總結,總結出GCD的經典使用場景。原始碼只提供Swift版本。因為要上班,計劃一個月內完成。每週兩篇。
原創Blog,轉載請註明出處
這個專欄地址
GCD
全稱:Grand Central Dispatch
簡介:GCD是對多執行緒、多核開發較完整的封裝。在使用GCD的時候,系統會自動根據CPU使用情況進行排程,所以GCD是
一個簡單易用,但是效果很好地多執行緒多核開發工具。
要注意的地方:
1、慎用fork()函式(不是十分清楚流程不要用)
2、GCD是C語言級別的API,所以不會抓到異常,在一個提交到GCD的任務完成之前,應當處理完異常。
教程一
教程一涵蓋了
1、GCD全域性佇列的四個優先順序
2、幾種本文使用到的GCD型別
3、dispatch_async/dispatch_async_f
4、dispatch_sync/dispatch_sync_f
一、概念與型別
對於GCD來說,所有的執行都放到佇列中(queue),佇列的特點是FIFO(先提交的先執行)。
GCD的佇列分為幾種,主佇列(main),全域性佇列(global),使用者建立佇列(create)
對於全域性佇列,預設有四個,分為四個優先順序
- #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:優先順序最高,在default,和low之前執行
DISPATCH_QUEUE_PRIORITY_DEFAULT 預設優先順序,在low之前,在high之後
DISPATCH_QUEUE_PRIORITY_LOW 在high和default後執行
DISPATCH_QUEUE_PRIORITY_BACKGROUND:提交到這個佇列的任務會在high優先順序的任務和已經提交到background佇列的執行完後執行。官方文件:(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.)
幾種使用到的型別
- typealias dispatch_queue_t = NSObject //輕量級的用來描述執行任務的佇列
- typealias dispatch_block_t = () -> Void //佇列執行的閉包(Objective C中的block)
幾個概念
非同步提交的任務立刻返回,在後臺佇列中執行
同步提交的任務在執行完成後才會返回
並行執行(全域性佇列)提交到一個佇列的任務,比如提交了任務1和任務2,在任務1開始執行,並且沒有執行完畢時候,任務2就可以開始執行。
序列執行(使用者建立佇列) 提交到一個佇列中的任務,比如提交了任務1和任務2,只有任務1結束後,任務2才可執行
注意:提交到佇列中的任務是序列執行,還是並行執行由佇列本身決定。
二、示例詳解
- func dispatch_async(_ queue: dispatch_queue_t!,
- _ block: dispatch_block_t!)
queue 提交到的佇列,佇列的型別決定了是序列還是並行執行佇列中的任務
block 執行的閉包
- func dispatch_async_f(_ queue: dispatch_queue_t!,
- _ context: UnsafeMutablePointer<Void>,
- _ work: dispatch_function_t)
queue 提交到的佇列,佇列的型別決定了是序列還是並行執行佇列中的任務
context 傳遞給work的引數
work 執行的函式(C語言函式)
dispatch_sync 和 dispatch_sync的引數和上述對應一致,所以不再列出
總得來說帶有後綴_f(比如dispatch_sync_f,dispatch_after_f)就是提交給佇列一個C語言函式,因為極少用到這種形式,這裡僅給出一個簡單例子,後面的涉及到_f的都略過。1、dispatch_async/dispatch_sync
功能:提交到佇列中非同步/同步執行
本示例:下載一張圖片,圖片下載完畢後通知UI改變
注意:要改變UI必須在主佇列上執行
這裡用到了一個獲取全域性佇列的函式
- func dispatch_get_global_queue(_ identifier: Int,
- _ flags: UInt) -> dispatch_queue_t!
建立一個基於單頁面的Swift工程,然後在ViewController.swift中,
- class 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()
- }
- }
然後,我們觀察dispatch_sync
只需要修改這一行即可
- dispatch_sync(globalQueueDefault,0){
執行,觀察下效果:view載入很慢,但是在載入的時候,圖片下載完了。UI已經改變。可以打在這一行打斷點,會發現非同步執行會立刻返回,同步執行會等待執行結束後返回。
所以,當我們有一件非常耗時的事情,放到後臺佇列中去做,等做完了通知UI改變,是不會阻塞UI,降低使用者體驗的。
2、dispatch_async_f/dispatch_sync_f
簡單的例項,把一個C函式提交給佇列
首先,建立一個基於單頁面的swift工程,命名為testForCSDN,然後再新建一個C語言檔案,命名為hwcText->點選包括標頭檔案->點選包含Bridging-Header.h
這樣,工程裡多了三個檔案
hwcTest.c
hwcTest.h
testForCSDN-Bridging-Header.h
附上完整的程式碼
testForCSDN-Bridging-Header.h
- #import "hwcTest.h"
hwcTest.h
- #include <stdio.h>
- #include <unistd.h>
- typedefvoid (*hwcTestForGCD)(void*);
- hwcTestForGCD getFuncPointer();
hwcTest.c
- #include "hwcTest.h"
- void realFunction(void *input){
- for(int i = 0;i < 5;i++){
- printf("%d\n",i);
- sleep(1);
- }
- }
- hwcTestForGCD getFuncPointer(){
- return realFunction;
- }
- class 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()
- }
- }
- 0
- dispatch is over
- 1
- 2
- 3
- 4
然後,我們同樣改成dispatch_sync後執行,發現輸出
- 0
- 1
- 2
- 3
- 4
- 5
- dispatch is over
三、理解下並行佇列和序列佇列
使用一或者二中的工程都可以,修改ViewController.swft中的程式碼就可以
這裡用到了一個函式
- func dispatch_queue_create(_ label: UnsafePointer<Int8>,
- _ attr: dispatch_queue_attr_t!) -> dispatch_queue_t!
label String型別的佇列標示符,通常取做com.companyname.productname.functionname
attr 兩種型別。DISPATCH_QUEUE_SERIAL建立一個順序執行佇列, DISPATCH_QUEUE_CONCURRENT建立同時執行佇列
ViewController的完整程式碼,這裡提交兩個任務,通過輸出來判斷是並行佇列,還是序列佇列
- 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()
- }
- }
這裡執行輸出為:
- 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