1、GCD是異步執行任務的技術之一,通常將應用程序中記敘的線程管理用的代碼在系統級中是實現。 html
開發者只須要定義想要執行的任務並追加到適當的Dispatch Queue中,GCD就能生成必要的線程並計劃執行任務。 編程
2、多線程編程 多線程
因爲使用多線程的程序能夠在某個線程和其餘線程之間反覆屢次進行上下文切換,所以看上去就好像一個CPU核可以並行的執行多個線程同樣,並且在具備多個CPU核的狀況下,就不是「看上去像」了,而是真的提供了多個CPU核並行執行任務的多個線程的技術。 併發
多線程編程容易發生各類編程問題:好比多個線程更新相同的資源會致使數據的不一致(數據競爭)、中止等待事件的線程會致使多個線程相互持續等待(死鎖)、使用太多線程會消耗大量的內存資源等等。 app
儘管會有問題,可是爲何還要用呢? 異步
在應用程序啓動時,經過最早執行的線程,即主線程來描繪用戶界面、處理用戶觸摸事件等,可是若是在該主線程中進行長時間的處理,就會妨礙主線程中被稱爲RunLoop的主循環的執行,從而致使不能跟新用戶界面,應用程序的畫面長時間停滯等問題。 async
3、GCD 的 API 函數
1.Dispatch Queue oop
開發者要作的只是定義想要執行的任務並追加到適當的DispatchQueue中。 spa
在Block中定義想要執行的任務,而後追加到Dispatch Queue中
Dispatch Queue是執行處理的等待隊列,經過dispatch_async等API,在Block語法中記敘想要執行的處理並將其追加到Dispatch Queue中,Dispatch Queue按照追加的順序(FIFO)執行處理。
另外,在執行處理時存在兩種Dispatch Queue:
Dispatch Queue的種類
說明
Serial Dispatch Queue
等待如今執行中處理結束
Concurrent Dispatch Queue
不等待如今執行中處理結束
解釋說明一下:
(1) Serial Dispatch Queue:就是要等待如今執行中處理結束後才能夠進行下一個任務的執行處理,假如如今有blk1,blk2,blk3,在Serial Dispatch Queue中,那麼同時執行處理數只能是一個,並且按按添加順序FIFO進行處理,即先執行blk1,執行結束後再執行blk2,執行結束再進行blk3的執行。
(2) Concurrent Dispatch Queue:就是一個線程的執行不等待如今(當前)執行中的任務處理結束就能夠開始另外一個任務的執行處理。一樣假若有blk1,blk2,blk3在Concurrent Dispatch Queue中,那麼首先執行blk1,無論blk1是否執行處理結束,都開始執行後面的blk2,無論blk2是否執行結束,都開始執行後面的blk2。
這樣雖然不用等待處理結束,能夠並行執行多個任務處理,可是並行處理數取決於當前系統的狀態,有它決定Concurrent Dispatch Queue中並行執行的處理數。所謂並行執行就是使用多個線程來同時執行多個處理任務(block中的執行任務)。
SerialDispatchQueue同時只能執行一個追加處理
ConcurrentDispatchQueue並行執行多個追加處理
雖然SerialDispatchQueue ConcurrentDispatchQueue受到系統資源的限制,可是用dispatch_queue_create能夠生成任意多個Dispatch Queue
當生成多個SerialDispatchQueue時,各個SerialDispatchQueue將並行執行,雖然一個SerialDispatchQueue同時只能執行一個追加處理,可是若是將處理分別追加到4個
Serial Dispatch Queue中,各個Serial Dispatch Queue執行一個,即爲同時執行4個處理
可是生成Serial Dispatch Queue的個數受系統限制
爲了不多線程編程的問題之一---數據競爭,就可使用Serial Dispatch Queue。
當想並行執行且不發生數據競爭等問題時就應該使用Concurrent Dispatch Queue。
[cpp]
//如下代碼是兩種生成Serial Dispatch Queue的方式
dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("cn.edu.scnu.mySerialDispatchQueue", NULL);
// dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("cn.edu.scnu.mySerialDispatchQueue", DISPATCH_QUEUE_SERIAL);
//如下代碼是兩種生成Serial Dispatch Queue的方式
dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("cn.edu.scnu.mySerialDispatchQueue", NULL);
// dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("cn.edu.scnu.mySerialDispatchQueue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_create,該方法中的第一個參數指定SerialDispatchQueue的名稱,DispatchQueue的名稱推薦使用應用程序ID之中逆序全程域名,第二個參數指定爲NULL(或者DISPATCH_QUEUE_SERIAL)時即表示生成的是Serial Dispatch Queue,指定爲DISPATCH_QUEUE_CONCURRENT時即表示生成的是Concurrent Dispatch Queue
[cpp]
//如下代碼生成ConcurrentDispatchQueue
dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create("cn.edu.scnu.myConcurrentDispatchQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(myConcurrentDispatchQueue, ^{
NSLog(@"block on my ConcurrentDispatchQueue");
});
//如下代碼生成ConcurrentDispatchQueue
dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create("cn.edu.scnu.myConcurrentDispatchQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(myConcurrentDispatchQueue, ^{
NSLog(@"block on my ConcurrentDispatchQueue");
});
二、MainDispatch Queue 和 Global Dispatch Queue
實際上不用特地生成DispatchQueue,系統也會提供幾個給咱們,就是Main DispatchQueue 和 Global Dispatch Queue
Main Dispatch Queue就是主線程中執行的Dispatch Queue,由於主線程只有一個,因此Main DispatchQueue天然就是 Serial Dispatch Queue
[cpp]
//獲取Main Dispatch Queue
dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();
//獲取Main Dispatch Queue
dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();
GlobalDispatch Queue是全部應用程序都可以使用的Concurrent Dispatch Queue,沒有必要經過dispatch_queue_create方法逐個生成Concurrent Dispatch Queue,只要獲
取GlobalDispatch Queue使用便可。
Global Dispatch Queue有四個優先級:High Priority,Default Priority,Low Priority,Background Priority
[cpp]
//獲取高優先級的的Global Dispatch Queue
/*
DISPATCH_QUEUE_PRIORITY_HIGH
DISPATCH_QUEUE_PRIORITY_DEFAULT
DISPATCH_QUEUE_PRIORITY_LOW
DISPATCH_QUEUE_PRIORITY_BACKGROUND
*/
dispatch_queue_t globalDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
//第一個參數指定Global Dispatch Queue的優先級,第二個參數指定爲0
//獲取高優先級的的Global Dispatch Queue
/*
DISPATCH_QUEUE_PRIORITY_HIGH
DISPATCH_QUEUE_PRIORITY_DEFAULT
DISPATCH_QUEUE_PRIORITY_LOW
DISPATCH_QUEUE_PRIORITY_BACKGROUND
*/
dispatch_queue_t globalDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
//第一個參數指定Global Dispatch Queue的優先級,第二個參數指定爲0
三、dispatch_set_target_queue
dispatch_queue_create函數生成的Dispatch Queue無論是Serial Dispatch Queue仍是Concurrent Dispatch Queue,都是使用與默認優先級的Global Dispatch Queue相同執
行優先級的線程
若是想變動生成的Dispatch Queue的執行優先級要使用dispatch_set_target_queue方法。
[cpp]
dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("cn.edu.scnu.mySerialDispatchQueue", NULL);
dispatch_queue_t globalDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_set_target_queue(mySerialDispatchQueue, globalDispatchQueue);
//指定要變動執行優先級的dispatch queue爲dispatch_set_target_queue方法的第一個參數,指定與要使用的執行優先級相同優先級的Global Dispatch Queue爲第二個參數(目標)
//第一個參數不能夠指定爲系統提供的Main Dispatch Queue 和 Global Dispatch Queue
dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("cn.edu.scnu.mySerialDispatchQueue", NULL);
dispatch_queue_t globalDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_set_target_queue(mySerialDispatchQueue, globalDispatchQueue);
//指定要變動執行優先級的dispatch queue爲dispatch_set_target_queue方法的第一個參數,指定與要使用的執行優先級相同優先級的Global Dispatch Queue爲第二個參數(目標)
//第一個參數不能夠指定爲系統提供的Main Dispatch Queue 和 Global Dispatch Queue
四、dispatch_after
想在指定時間後執行處理的狀況,可使用 dispatch_after 方法來實現
[cpp]
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
NSLog(@"waited at least 2.0 seconds.");
});
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
NSLog(@"waited at least 2.0 seconds.");
});
值得注意的是,dispatch_after方法並非在指定時間後執行處理任務,而是在指定時間後追加處理到dispatch queue中,上面的代碼在2秒後用dispatch_after方法追加
block到Main Dispatch Queue中,由於Main Dispatch Queue在主線程的RunLoop中執行,因此好比每一個1/60秒執行的RunLoop中,Block最快在2秒後執行,最慢在2秒+1/60
秒後執行,並且在Main Dispatch Queue中又大量處理追加或者主線程的處理自己有延時時,這個時間會更長。
dispatch_after這個方法的第二個參數指定要追加的dispatch queue,第三個參數指定要執行處理的Block,第一個參數是指定時間用的dispatch_time_t類型的值,在使用
dispatch_after的時候,編譯器會自動幫你生成這些代碼,只需修改delayInSeconds就能夠了。
五、Dispatch Group
在追加到dispatch queue中的多個處理所有結束後想執行結束處理任務,這種狀況會常常出現。只使用一個Serial Dispatch Queue時,只要將想執行的所有處理都追加到該
Serial Dispatch Queue種並在最後追加結束處理就能夠實現。可是在使用Concurrent Dispatch Queue時或者同時使用多個dispatch queue時,就會有些複雜了,在這種狀況下
就應該使用Dispatch Group
[cpp]
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{NSLog(@"blk1");});
dispatch_group_async(group, queue, ^{NSLog(@"blk2");});
dispatch_group_async(group, queue, ^{NSLog(@"blk3");});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"done");
});
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{NSLog(@"blk1");});
dispatch_group_async(group, queue, ^{NSLog(@"blk2");});
dispatch_group_async(group, queue, ^{NSLog(@"blk3");});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"done");
});
由於向 Global Dispatch Queue即Concurrent Dispatch Queue追加處理任務,多個線程並行執行,因此追加處理任務的執行順序是不定的,執行時順序會發生變化,可是主線程中執行結果輸出done確定是最後的。
下面稍微解釋一下上面的那段代碼,上面由3個輸出任務的block組成一個dispatch group,並把這個dispatch group添加到dispatch queue中執行,當dispatch group中的
block任務執行完畢後,dispatch_group_notify方法就會被執行到,因此它的第一個參數是group,表示其被監視。在追加到dispatch group中的所有執行處理任務執行結束後,
將第三個參數中的block任務添加到第二個參數的dispatch queue中執行,注意此時dispatch group中的因此執行任務已經執行結束了。
另外,在dispatch group中也可使用 dispatch_group_wait方法僅等待所有處理執行結束。
[cpp]
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{NSLog(@"blk1");});
dispatch_group_async(group, queue, ^{NSLog(@"blk2");});
dispatch_group_async(group, queue, ^{NSLog(@"blk3");});
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{NSLog(@"blk1");});
dispatch_group_async(group, queue, ^{NSLog(@"blk2");});
dispatch_group_async(group, queue, ^{NSLog(@"blk3");});
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
在這個方法中的第二個參數指定等待時間,這裏使用DISPATCH_TIME_FOREVER意味着永久等待,只要屬於dispatch group中的處理還沒有執行結束,就會一直等待,中途不能取消。
固然如同dispatch——after方法中那樣,也能夠指定等待時間爲1秒等等。
[cpp]
//這裏指定等待時間1s,即1s後查看dispatch group中的處理是否所有執行結束
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull*NSEC_PER_SEC);
long result = dispatch_group_wait(group, time);
if (result == 0) {
//屬於dispatch group中的所有處理都執行結束
}
else {
//屬於dispatch group的某一個處理還在執行
}
//這裏指定等待時間1s,即1s後查看dispatch group中的處理是否所有執行結束
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull*NSEC_PER_SEC);
long result = dispatch_group_wait(group, time);
if (result == 0) {
//屬於dispatch group中的所有處理都執行結束
}
else {
//屬於dispatch group的某一個處理還在執行
}
[cpp]
//這裏也能夠指定DISPATCH_TIME_NOW,則不用任何等待便可判斷屬於dispatch group中的處理是否所有執行結束
long result = dispatch_group_wait(group, DISPATCH_TIME_NOW);
//這裏也能夠指定DISPATCH_TIME_NOW,則不用任何等待便可判斷屬於dispatch group中的處理是否所有執行結束
long result = dispatch_group_wait(group, DISPATCH_TIME_NOW);
六、dispatch_barrier_async
[cpp]
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(queue, ^{
//表示執行數據讀取任務
NSLog(@"blk1_reading");
});
dispatch_async(queue, ^{
NSLog(@"blk2_reading");
});
dispatch_async(queue, ^{
//表示執行數據寫入處理任務
NSLog(@"blk1_writting");
});
dispatch_async(queue, ^{
NSLog(@"blk3_reading");
});
dispatch_async(queue, ^{
NSLog(@"blk4_reading");
});
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(queue, ^{
//表示執行數據讀取任務
NSLog(@"blk1_reading");
});
dispatch_async(queue, ^{
NSLog(@"blk2_reading");
});
dispatch_async(queue, ^{
//表示執行數據寫入處理任務
NSLog(@"blk1_writting");
});
dispatch_async(queue, ^{
NSLog(@"blk3_reading");
});
dispatch_async(queue, ^{
NSLog(@"blk4_reading");
});
若是像上面那樣簡單的在dispatch_async方法中添加寫入數據處理的任務,那麼根據Concurrent Dispatch Queue並行執行的性質,就頗有可能不是按照上面的添加處理任務的
順序執行,那麼在blk3_reading 和 blk4_reading執行讀取數據的時候,blk1_writting進行寫入數據的處理尚未執行到,那麼後兩次的讀取數據操做讀取到的數據就與指望中
的不符了。
解決這個問題的處理就是 使用 dispatch_barrier_async
[cpp]
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(queue, ^{
//表示執行數據讀取任務
NSLog(@"blk1_reading");
});
dispatch_async(queue, ^{
NSLog(@"blk2_reading");
});
dispatch_barrier_async(queue, ^{
//表示執行數據寫入處理任務
NSLog(@"blk1_writting");
});
dispatch_async(queue, ^{
NSLog(@"blk3_reading");
});
dispatch_async(queue, ^{
NSLog(@"blk4_reading");
});
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(queue, ^{
//表示執行數據讀取任務
NSLog(@"blk1_reading");
});
dispatch_async(queue, ^{
NSLog(@"blk2_reading");
});
dispatch_barrier_async(queue, ^{
//表示執行數據寫入處理任務
NSLog(@"blk1_writting");
});
dispatch_async(queue, ^{
NSLog(@"blk3_reading");
});
dispatch_async(queue, ^{
NSLog(@"blk4_reading");
});
使用dispatch_barrier_async方法,它會等待在它以前添加到 Concurrent Dispatch Queue的全部處理執行結束後,才執行該處理,而後等待該處理結束後,才接着處理後續添
加到Concurrent Dispatch Queue中的處理任務。固然在dispatch_barrier_async方法以前和以後添加的處理任務能夠併發執行,即不保證執行順序,可是能夠確保
dispatch_barrier_async方法添加的任務必定是隻能同時執行一個,按其添加任務順序執行的,就是說,執行完blk1_reading和blk2_reading的讀取數據任務後,纔是進行
blk1_writting的寫入數據任務,而後纔是執行接着的讀取數據的任務。
七、dispatch——sync
dispatch_async方法中的async意味着「非同步」,就是將指定的block非同步的添加到dispatch qeueue中,dispatch_async方法不作任何等待。
dispatch_sync方法中的sync意味着「同步」,也就是將指定的block同步追加到dispatch queue中,在追加block的過程結束以前,dispatch_sync方法會一直等待。
一旦調用dispatch_sync,那麼在指定的處理執行結束以前,該方法不會返回,dispatch_sync方法能夠簡化代碼,也能夠說是簡易版的dispatch_group_wait方法
dispatch_sync方法使用簡單,可是容易引發死鎖
[cpp]
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
NSLog(@"引發死鎖!");
});
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
NSLog(@"引發死鎖!");
});
上面的代碼在主線程中執行指定的block,並等待其執行結束,可是其實在主線程中就是在執行這些代碼,因此就形成了死鎖。
八、dispatch_apply
dispatch_apply 方法是 dispatch_sync 方法和Dispatch Group的關聯API,該方法按指定的次數將指定的Block追加到指定的Dispatch Queue中,並等待所有處理執行結束
[cpp]
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(10, queue, ^(size_t index){
NSLog(@"%zu",index);
});
NSLog(@"done");
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(10, queue, ^(size_t index){
NSLog(@"%zu",index);
});
NSLog(@"done");
由於是在Global Dispatch Queue中執行處理,因此各個處理的執行時間不定,也就是說輸出1 2 3 ...的順序不定。可是輸出結果done一定是在最後的位置上的。由於dispatch_apply會等待因此的處理任務執行結束。
dispatch_apply 中的第一個參數是重複次數,第二個參數是追加對象的Dispatch Queue,第三個參數爲追加的處理block,注意帶參數
[cpp]
//假如對一個NSArray類對象的全部元素執行處理時,沒必要一個個編寫for循環
NSArray *array = [[NSArray alloc] initWithObjects:@"string1",@"string2",@"string3", nil];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply([array count], queue, ^(size_t index){
NSLog(@"%zu : %@",index,[array objectAtIndex:index]);
});
//假如對一個NSArray類對象的全部元素執行處理時,沒必要一個個編寫for循環
NSArray *array = [[NSArray alloc] initWithObjects:@"string1",@"string2",@"string3", nil];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply([array count], queue, ^(size_t index){
NSLog(@"%zu : %@",index,[array objectAtIndex:index]);
});
因爲dispatch_apply方法也與dispatch_sync方法相同,會等待處理執行結束,所以推薦在dispatch_async函數中非同步的執行dispatch_apply方法。
例如:
[cpp]
NSArray *array = [[NSArray alloc] initWithObjects:@"string1",@"string2",@"string3", nil];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//在Glocbal Dispatch Queue中非同步執行
dispatch_async(queue, ^{
//等待dispatch_apply方法中的所有處理執行結束
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply([array count], queue, ^(size_t index){
NSLog(@"%zu : %@",index,[array objectAtIndex:index]);
});
//dispatch_apply方法中的所有處理任務執行結束
dispatch_async(dispatch_get_main_queue(), ^{
//在主線程中執行處理
NSLog(@"done");
});
});
NSArray *array = [[NSArray alloc] initWithObjects:@"string1",@"string2",@"string3", nil];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//在Glocbal Dispatch Queue中非同步執行
dispatch_async(queue, ^{
//等待dispatch_apply方法中的所有處理執行結束
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply([array count], queue, ^(size_t index){
NSLog(@"%zu : %@",index,[array objectAtIndex:index]);
});
//dispatch_apply方法中的所有處理任務執行結束
dispatch_async(dispatch_get_main_queue(), ^{
//在主線程中執行處理
NSLog(@"done");
});
});
九、dispatch_suspend 和 dispatch_resume
[cpp]
//掛起指定的dispatch queue
dispatch_suspend(<#dispatch_object_t object#>)
//恢復指定的dispatch queue
dispatch_resume(<#dispatch_object_t object#>)
//這些方法對已經執行的處理沒有影響,掛起後,追加到dispatch queue中但還沒有處理的在此以後中止執行,而恢復後則使得這些處理可以繼續執行。
//掛起指定的dispatch queue
dispatch_suspend(<#dispatch_object_t object#>)
//恢復指定的dispatch queue
dispatch_resume(<#dispatch_object_t object#>)
//這些方法對已經執行的處理沒有影響,掛起後,追加到dispatch queue中但還沒有處理的在此以後中止執行,而恢復後則使得這些處理可以繼續執行。
十、dispatch_once
dispatch_once方法保證在應用程序執行中只執行一次指定處理的API。
[cpp]
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//code to be executed once
});
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//code to be executed once
});
轉載自:http://www.2cto.com/kf/201307/231244.html 做者:Crayon_DyS