Dispatch_group
GCD頭文件group.h中談到,可以將一組block提交到調度組(dispatch_group)中,執行逐個串行回調,下面來看看相關函數。
函數申明與理解
-
dispatch_group_t dispatch_group_create(void);
//創建一個調度組,釋放調度組使用dispatch_release()函數,創建成功返回一個dispatch_group調度組,失敗則返回NULL. -
void dispatch_group_async(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block);
//提交一個閉包函數(block)到queue中,並關聯到指定的group調度組.通過typedef void (^dispatch_block_t)(void);
我們可以發現,該函數無法給block傳遞參數.
1. group 指定的調度組,block的關聯調度組。
2. queue 提交閉包函數(block)的隊列。
3. block 提交到指定queue的閉包函數block。 -
void dispatch_group_async_f(dispatch_group_t group,dispatch_queue_t queue,void *_Nullable context,dispatch_function_t work);
//提交一個函數指針(dispatch_function_t)到queue中,並關聯到指定的group調度組,函數返回void.
1. group 指定的調度組,block的關聯調度組。
2. queue 提交閉包函數(block)的隊列。
3. context 傳遞到函數中的的參數。
4. work 在指定的queue中的指定函數。 -
long dispatch_group_wait(dispatch_group_t group, dispatch_time_t timeout);
//執行等待,等待所有關聯到group調度組的block執行完成,或者等待timeout發生超時,當在超時時間timeout內執行完了所有的block函數,則返回0,否則返回非0值。
1. group 給定調度組
2. timeout 如果group調度組里邊的block執行時間非常長,函數的等待時間. -
void dispatch_group_notify(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block);
//該函數指定了一個block,當group調度組里邊的所有block都執行完成時,將通知block關聯到group中,並加入到給定的queue隊列里,當group調度組當前沒有任何block關聯的時候將立即將block提交到queue隊列,並與group調度組關聯,該函數返回void.
1. group 給定的調度組
2. queue 給定的隊列.
3. 給定的閉包函數. -
void dispatch_group_notify_f(dispatch_group_t group,dispatch_queue_t queue,void *_Nullable context,dispatch_function_t work);
//與disptch_group_notify類似,提交的一個函數work作為執行體,context是執行時傳遞的參數,該函數返回void. -
void dispatch_group_enter(dispatch_group_t group);
-
void dispatch_group_leave(dispatch_group_t group);
//這一對函數調用一次意味着非使用dispatch_group_async方式,將一個block提交到指定的queue上並關聯到group調度組.兩個函數必須成對出現。
實際例子
- 環境變量與函數
//create one group.
dispatch_group_t _group;
dispatch_queue_t _serialQ;
void dispatch_group_test() {
_group = dispatch_group_create();
_serialQ = dispatch_queue_create("this.is.a.serial.queue", DISPATCH_QUEUE_SERIAL);
// one_test_function_use();
}
dispatch_group_test函數下面會繼續提到,標記為“入口函數”
定義一個調度組_group
和一個串行隊列_serialQ
,下面所有的測試函數都有效.
- dispatch_group_async函數的使用實例
void dispatch_group_async_use() {
void (^noParameterHandle)(void) = ^(void) {
NSLog(@"execute block");
};
for (NSInteger index = 0; index < 5; index ++) {
dispatch_group_async(_group, _serialQ,noParameterHandle);
}
}
執行結果:
2017-03-01 17:33:23.809238 dispatch_data[17920:907260] execute block
2017-03-01 17:33:23.809343 dispatch_data[17920:907260] execute block
2017-03-01 17:33:23.809358 dispatch_data[17920:907260] execute block
2017-03-01 17:33:23.809371 dispatch_data[17920:907260] execute block
2017-03-01 17:33:23.809381 dispatch_data[17920:907260] execute block
可以從實例中看出,使用dispatch_group_async函數關聯的block無法傳遞參數.
- dispatch_group_async_f函數實踐示例
先實現一個類型為void ()(void *)的C函數
void function_t_use(void *value) {
char *cString = value;
NSLog(@"value is : %@",[NSString stringWithUTF8String:cString]);
}
下面是測試函數⤵️
void dispatch_group_async_f_use() {
for (NSInteger index = 0; index < 5; index ++) {
char *cString = (char *)[NSString stringWithFormat:@"%ld",index].UTF8String;
dispatch_group_async_f(_group, _serialQ, cString, function_t_use);
}
}
執行結果:
2017-03-01 18:00:39.641617 dispatch_data[18368:930399] value is : 0
2017-03-01 18:00:39.641656 dispatch_data[18368:930399] value is : 1
2017-03-01 18:00:39.641673 dispatch_data[18368:930399] value is : 2
2017-03-01 18:00:39.641688 dispatch_data[18368:930399] value is : 3
2017-03-01 18:00:39.641700 dispatch_data[18368:930399] value is : 4
dispatch_group_async_f_use 允許傳遞參數到function中,需要注意的是傳遞的參數盡量使用char *,測試時使用int *不能正確的得到結果.
- long dispatch_group_wait(group,timeout) 函數實踐示例
當group關聯的block實行完畢時 long = 0 屬於正常情況,
void dispatch_group_waite_normal_use() {
void (^noParameterHandle)(void) = ^(void) {
NSLog(@"execute block");
};
dispatch_group_async(_group, _serialQ, noParameterHandle);
NSLog(@"will waite...");
long count = dispatch_group_wait(_group, dispatch_time(DISPATCH_TIME_NOW,10 * NSEC_PER_SEC));
NSLog(@"count: %ld",count);
}
返回結果:
2017-03-01 18:21:39.823695 dispatch_data[18466:940513] will waite...
2017-03-01 18:21:39.823699 dispatch_data[18466:940543] execute block
2017-03-01 18:21:39.823762 dispatch_data[18466:940513] count: 0
可以看出,block注冊到了_group中,屬於異步函數,當前線程繼續向下執行,打印willwaite...,之后調用dispatch_group_waite函數進入等待,由於單次block回調非常快,不會超過timeout的時間,最終打印count = 0,當timeout超時group還有關聯的任務時,將返回非0值錯誤。
void dispatch_group_waite_timeout_use() {
void (^noParameterHandle)(void) = ^(void) {
sleep(1);
NSLog(@"execute block");
};
for (NSUInteger index = 0; index < 5; index ++) {
dispatch_group_async(_group, _serialQ, noParameterHandle);
}
NSLog(@"will waite...");
long count = dispatch_group_wait(_group, dispatch_time(DISPATCH_TIME_NOW,3 * NSEC_PER_SEC));
NSLog(@"count: %ld",count);
}
執行結果:
2017-03-01 18:31:02.762822 dispatch_data[18547:945276] will waite...
2017-03-01 18:31:03.767823 dispatch_data[18547:945310] execute block
2017-03-01 18:31:04.770983 dispatch_data[18547:945310] execute block
2017-03-01 18:31:05.763463 dispatch_data[18547:945276] count: 49
2017-03-01 18:31:05.772842 dispatch_data[18547:945310] execute block
2017-03-01 18:31:06.777980 dispatch_data[18547:945310] execute block
2017-03-01 18:31:07.779768 dispatch_data[18547:945310] execute block
該測試函數指定dispatch_group_wait函數的timeout是3秒,在執行完兩次for循環后已經超時,最后得到的count值非0 count=49.
實際上該測試函數隱藏着一個值得討論的地方:
在noParameterHandle這個閉包函數中,直接使用sleep(1),閉包執行的隊列是_serialQ,
對於整個dispatch_group_waite_timeout_use函數,測試的時候是放在了mainQueue去執行,也就是dispatch_group_wait函數是在mainQueue中執行,此時跟閉包執行的隊列不一致,各自在自己的隊列執行,得到了上面的結果。
假設整個dispatch_group_waite_timeout_use函數的執行體所在的隊列就是_serialQ,而閉包所在的隊列也是_serialQ,所以就相當於6個task都提交到了_serialQ,task1代表dispatch_group_waite_timeout_use函數,task2..6代表noParameterHandle(有一個for循環),由於是串行執行,當代碼執行到dispatch_group_wait函數時,整個_serialQ將進入等待,3秒之后,打印count值,之后再串行執行5個閉包task.
更換上面提到的“入口函數”,實踐討論的內容,代碼如下:
void dispatch_group_test() {
_group = dispatch_group_create();
_serialQ = dispatch_queue_create("this.is.a.serial.queue", DISPATCH_QUEUE_SERIAL);
dispatch_async(_serialQ, ^{
dispatch_group_waite_timeout_use();
});
}
打印結果:
2017-03-01 18:36:26.547770 dispatch_data[18637:949068] will waite...
2017-03-01 18:36:29.549184 dispatch_data[18637:949068] count: 49
2017-03-01 18:36:30.550143 dispatch_data[18637:949068] execute block
2017-03-01 18:36:31.551091 dispatch_data[18637:949068] execute block
2017-03-01 18:36:32.552570 dispatch_data[18637:949068] execute block
2017-03-01 18:36:33.557777 dispatch_data[18637:949068] execute block
2017-03-01 18:36:34.562879 dispatch_data[18637:949068] execute block
- void dispatch_group_notify(group,queue,block);函數實踐示例
當group所關聯的block全部執行結束時,會立馬將給定block關聯到group中,並在給定的queue中執行.代碼如下:
void dispatch_grout_notify_use() {
void (^noParameterHandle)(void) = ^(void) {
NSLog(@"execute block");
};
for (NSUInteger index = 0; index < 5; index ++) {
dispatch_group_async(_group, _serialQ, noParameterHandle);
}
dispatch_group_notify(_group, _serialQ, ^{
NSLog(@"executing the notify block...");
});
}
執行結果:
2017-03-01 18:55:06.172181 dispatch_data[18706:955792] execute block
2017-03-01 18:55:06.172216 dispatch_data[18706:955792] execute block
2017-03-01 18:55:06.172229 dispatch_data[18706:955792] execute block
2017-03-01 18:55:06.172240 dispatch_data[18706:955792] execute block
2017-03-01 18:55:06.172249 dispatch_data[18706:955792] execute block
2017-03-01 18:55:06.172262 dispatch_data[18706:955792] executing the notify block...
由於dispatch_group_async是異步調用的,而dispatch_group_notify是同步調用的,所以,從該示例可以可以得到上述結論,dispatch_group_notify可以用於需要指定task之間的順序時。
- void dispatch_group_enter(group)與dispatch_group_leave(group);函數實踐示例
當你的代碼無法使用dispatch_group_async函數去關聯一個block到給定的調度組時,可以使用這對函數達到相同的功能.這里使用它來達到dispatch_group_async的功能,代碼如下:
void dispatch_group_leave_enter_use() {
void (^noParameterHandle)(void) = ^(void) {
NSLog(@"execute block");
};
for (NSInteger index = 0; index < 5; index ++) {
dispatch_group_enter(_group);
dispatch_async(_serialQ, noParameterHandle);
dispatch_group_leave(_group);
//enter 和 leave 必須成對出現,否則會引發crash.
}
}
執行結果:
2017-03-01 19:02:53.657501 dispatch_data[18739:958841] execute block
2017-03-01 19:02:53.657781 dispatch_data[18739:958841] execute block
2017-03-01 19:02:53.657803 dispatch_data[18739:958841] execute block
2017-03-01 19:02:53.657816 dispatch_data[18739:958841] execute block
2017-03-01 19:02:53.657827 dispatch_data[18739:958841] execute block
可以看出,當無法使用dispatch_group_async函數時,可以使用dispatch_group_enter和leave達到相同的效果.
dispatch_group主題功能介紹完畢,水平有限,為不誤人子弟,如有錯誤之處,還請各位大神一定指出,在此謝過。
博主已經開通了博客地址: kobeluo,哪里有更豐富的資源,歡迎與我交流。
搭建博客方法:https://hexo.io/ http://liuhongjiang.github.io/hexotech/2012/11/21/how-to-build-blog/