ios GCD將異步轉換為同步
在開發(fā)中有時需要等網(wǎng)絡請求完成之后拿到數(shù)據(jù)做一些操作,而且有時是同時好幾個網(wǎng)絡請求同時發(fā)起。這時會有對異步操作進行更進一步控制的場景,不單網(wǎng)絡請求,有時一些其他本地文件,多張圖片處理等可能都會遇到這種操作,GCD中就有很多這方面處理的api。
1. 利用并發(fā)隊列和柵欄函數(shù)對異步操作進行控制。
// 創(chuàng)建隊列dispatch_queue_t queue = dispatch_queue_create("task", DISPATCH_QUEUE_CONCURRENT);
? ? // 添加任務dispatch_async(queue, ^{
? ? ? ? NSLog(@"1===task===%@", [NSThread currentThread]);
? ? });
? ? dispatch_async(queue, ^{
? ? ? ? NSLog(@"2===task===%@", [NSThread currentThread]);
? ? });
? ? dispatch_async(queue, ^{
? ? ? ? NSLog(@"3===task===%@", [NSThread currentThread]);
? ? });
? ? // 與dispatch_barrier_async區(qū)別就是它的block里代碼是否在主線程執(zhí)行dispatch_barrier_sync(queue, ^{
? ? ? ? NSLog(@"===barrier==%@", [NSThread currentThread]);
? ? });
? ? dispatch_async(queue, ^{
? ? ? ? NSLog(@"4===task===%@", [NSThread currentThread]);
? ? });
? ? dispatch_async(queue, ^{
? ? ? ? NSLog(@"5===task===%@", [NSThread currentThread]);
? ? });
? ? dispatch_async(queue, ^{
? ? ? ? NSLog(@"6===task===%@", [NSThread currentThread]);
? ? });
上述代碼打印如下:

從打印可以看出dispatch_barrier_sync柵欄函數(shù)后 task 4,5,6 在 task1,2,3 執(zhí)行完后才執(zhí)行的。
2. 使用調(diào)度組進行分發(fā)操作dispatch_group_t,代碼如下:
1dispatch_group_t group = dispatch_group_create(); 2 3? ? dispatch_group_enter(group); 4? ? dispatch_group_enter(group); 5// 一個真實的網(wǎng)絡請求 6NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 7dict[@"a"] =@"square"; 8dict[@"c"] =@"topic"; 9[MLNetService requestType:RequestTypeGet URL:kBaseUrl dict:dict sBlock:^(id result) {10NSLog(@"%@", result);11? ? ? ? dispatch_group_leave(group);12} fBlcok:^(NSError *error) {13NSLog(@"%@", error);14? ? ? ? dispatch_group_leave(group);15? ? }];1617// 一個真實的網(wǎng)絡請求18NSMutableDictionary *dict2 = [NSMutableDictionary dictionary];19dict2[@"a"] =@"square";20dict2[@"c"] =@"topic";21[MLNetService requestType:RequestTypeGet URL:kBaseUrl dict:dict2 sBlock:^(id result) {22NSLog(@"%@", result);23? ? ? ? dispatch_group_leave(group);24} fBlcok:^(NSError *error) {25NSLog(@"%@", error);26? ? ? ? dispatch_group_leave(group);27? ? }];2829//? ? dispatch_get_global_queue(0, 0)30dispatch_group_notify(group, dispatch_get_main_queue(), ^{31NSLog(@"任務完成==%@", [NSThread currentThread]);32});
上述代碼中dispatch_group_enter與dispatch_group_leave一定要成對出現(xiàn)。請求前調(diào)用?dispatch_group_enter,請求結束后調(diào)用?dispatch_group_leave ,只有當所有的 enter 都 leave后,dispatch_group_notify 的block才會執(zhí)行。所以上面代碼等兩個網(wǎng)絡請求結束后會打印任務完成。
3. 使用信號量dispatch_semaphore_t對并發(fā)進行控制
信號量這里可以看作是資源標識,只有當它信號數(shù)大于0才可以往后面執(zhí)行,它有三個對應的 api 。
dispatch_semaphore_create創(chuàng)建一個信號,并指定初始的信號數(shù)
dispatch_semaphore_signal使對應的信號數(shù)加1
dispatch_semaphore_wait使對應的信號數(shù)量減1,如果執(zhí)行到這行代碼時信號數(shù)量已經(jīng)為0,那么在指定時間后才會去執(zhí)行它后面的代碼,指定時間為它的第二個參數(shù),如果設置為DISPATCH_TIME_FOREVER將一直等待。
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
? ? dispatch_queue_t queue = dispatch_queue_create("task", DISPATCH_QUEUE_CONCURRENT);
? ? dispatch_async(queue, ^{
? ? ? ? NSLog(@"1===task===%@", [NSThread currentThread]);
? ? ? ? dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3* NSEC_PER_SEC)), queue, ^{
? ? ? ? ? ? dispatch_semaphore_signal(semaphore);
? ? ? ? });
? ? });
? ? dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
? ? dispatch_async(queue, ^{
? ? ? ? NSLog(@"2===task===%@", [NSThread currentThread]);
? ? });
上述代碼打印結果如下

上面信號量代碼中一開始創(chuàng)建 ?semaphore 信號數(shù)就是0,所以?dispatch_semaphore_wait 后面的代碼要等到信號數(shù)不為0才會去執(zhí)行,在 task1 執(zhí)行完畢后用?dispatch_semaphore_signal 給信號數(shù)加1,所以 task2 代碼就被執(zhí)行了。