在發起網絡請求時,我們一般會用異步請求,這裏我們以 AFNetWorking 爲例:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:@"http://octree.me/" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"Success");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
假如我們要執行多個異步請求,一般可以這麼寫
NSArray *urlStrings = @[ @"http://octree.me", @"http://google.com", @"http://github.com" ];
for(NSString urlString in urlStrings) {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"Success");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
}
假如我們需要在三個請求都完成或者失敗後進行一些處理,但是 manager 發起的請求時異步處理的,也就是說當 manager 調用 GET:parameters:success:failure 會立即返回,當請求成功或失敗後纔會調用各自的 block ,我們如何才能監控併發的異步事件呢?並且他們的完成順序以及完成時間都是不確定的。
當然,你可以用一組 bool 值或者其他的標識記錄每個任務的完成進度,但是這樣的代碼不僅醜陋,而且失去了擴展性。
這時候我們就可以用到 dispatch_group 了
dispatch_group 在任務組內的任務都完成的時候通過同步或者異步的方式通知你
dispatch_group 提供了兩種通知方式, dispatch_group_wait 和 dispatch_group_notify
dispatch_group_wait 會阻塞當前線程,知道任務都完成時纔會繼續執行下面的代碼
我們可以使用 dispatch_group_wait 這樣實現:
NSArray *urlStrings = @[ @"http://octree.me", @"http://google.com", @"http://github.com" ];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
dispatch_group_t requestGroup = dispatch_group_create();
for(NSString urlString in urlStrings) {
dispatch_group_enter(requestGroup);
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"Success");
dispatch_group_leave(requestGroup);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
dispatch_group_leave(requestGroup);
}];
}
dispatch_group_wait(requestGroup, DISPATCH_TIME_FOREVER);
dispatch_async(dispatch_get_main_queue(), ^{
//doSomething;
});
}];
因爲 dispatch_group_wait 會阻塞當前線程,所以我們要把他放到後臺執行,避免阻塞主線程。通過 dispatch_group_enter 和 dispatch_group_leave 手動通知任務的開始以及結束。 dispatch_group_wait 會阻塞當前線程,知道所有任務完成或者超時纔會繼續執行下面的代碼。
前面我們說過, dispatch_group 提供了兩種通知方式,我們已經瞭解了 dispatch_group_wait ,另一種是 dispath_group_notify ,這種方式相對於前面的顯得更爲靈活。
dispatch_group_notify 是通過異步的方式通知,所以,不會阻塞線程。於是,我們就可以這樣寫:
NSArray *urlStrings = @[ @"http://octree.me", @"http://google.com", @"http://github.com" ];
dispatch_group_t requestGroup = dispatch_group_create();
for(NSString urlString in urlStrings) {
dispatch_group_enter(requestGroup);
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"Success");
dispatch_group_leave(requestGroup);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
dispatch_group_leave(requestGroup);
}];
}
dispatch_group_notify(requestGroup, dispatch_get_main_queue(), ^{
//doSomething
});