核心知识点
dispatch_group_t通过dispatch_group_enter、dispatch_group_leave成对使用,并通过dispatch_group_notify监听所有加入到组中的任务完成状态dispatch_semaphore_t可以通过dispatch_semaphore_wait来阻塞当前线程、当接收到dispatch_semaphore_signal信号后继续执行下面代码,以此来控制任务执行的顺序dispatch_semaphore_wait等待信号量,信号量减1。当信号量< 0时会阻塞当前线程,根据传入的等待时间决定接下来的操作——如果永久等待将等到信号(signal)才执行下去
dispatch_semaphore_signal<br />释放信号量,信号量加1。当信号量>= 0 会执行wait之后的代码
1. 异步任务请求,结束后返回主线程刷新UI(最常用、最简单)
- (void)dispatch_async_main_queue{NSURL *url = [NSURL URLWithString:@"https://www.baidu.com"];NSMutableURLRequest *mRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:3];NSURLSessionDataTask *dataTask = [[NSURLSession sharedSession] dataTaskWithRequest:mRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {NSLog(@"请求结束线程:%@",[NSThread currentThread]);// 返回到主线程dispatch_async(dispatch_get_main_queue(), ^{NSLog(@"回到主线程:%@\n%@",response.URL,[NSThread currentThread]);});}];[dataTask resume];}
2. 异步 有序/无序 执行组任务,全部执行完毕返回主线程刷新UI

/// 组任务无序异步执行- (void)group_notify{NSArray *urls = @[@"https://www.sina.com",@"https://www.baidu.com",@"https://www.jd.com"];dispatch_group_t dispatchGroup = dispatch_group_create();for (NSString *urlString in urls) {NSURLSessionDataTask *dataTask = [self dataTaskWithURLString:urlString completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;if (error) {NSLog(@"error:%@",error);}else{NSLog(@"任务:%@-%ld\n请求结束线程:%@",response.URL,httpResponse.statusCode,[NSThread currentThread]);}dispatch_group_leave(dispatchGroup);}];[dataTask resume];dispatch_group_enter(dispatchGroup);}// 设置组任务的超时时常(需要时可以设置)dispatch_time_t timeout = dispatch_group_wait(dispatchGroup, dispatch_time(DISPATCH_TIME_NOW, 10 *NSEC_PER_SEC));if (timeout != 0) {// 可以在此处取消正在进行的组任务[[NSURLSession sharedSession] getAllTasksWithCompletionHandler:^(NSArray * _Nonnull tasks) {[tasks enumerateObjectsUsingBlock:^(__kindof NSURLSessionTask * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {if (obj.state != NSURLSessionTaskStateCompleted) {[obj cancel];}}];}];NSLog(@"组任务执行超时_%llu",timeout);}else{}dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{NSLog(@"组任务执行完毕,返回主线程进行操作");});}/// 组任务有序异步执行- (void)group_notify_semaphore{NSArray *urls = @[@"https://www.sina.com",@"https://www.baidu.com",@"https://www.jd.com"];dispatch_group_t dispatchGroup = dispatch_group_create();// 利用信号量来控制请求顺序dispatch_semaphore_t sem = dispatch_semaphore_create(0);for (NSString *urlString in urls) {NSURLSessionDataTask *dataTask = [self dataTaskWithURLString:urlString completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;if (error) {NSLog(@"error:%@",error);}else{NSLog(@"任务:%@-%ld\n请求结束线程:%@",response.URL,httpResponse.statusCode,[NSThread currentThread]);}dispatch_group_leave(dispatchGroup);// 释放信号量,信号量加1。当信号量>= 0 会执行wait之后的代码dispatch_semaphore_signal(sem);}];[dataTask resume];dispatch_group_enter(dispatchGroup);// 等待信号量,信号量减1。当信号量< 0时会阻塞当前线程,根据传入的等待时间决定接下来的操作——如果永久等待将等到信号(signal)才执行下去dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);}dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{NSLog(@"组任务执行完毕,返回主线程进行操作");});NSLog(@"...");}- (NSURLSessionDataTask *)dataTaskWithURLString:(NSString *)urlString completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler{NSURL *url = [NSURL URLWithString:urlString];NSMutableURLRequest *mRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:3];NSURLSessionDataTask *dataTask = [[NSURLSession sharedSession] dataTaskWithRequest:mRequest completionHandler:completionHandler];return dataTask;}
group_notify

group_notify_semaphore
3. 异步分组执行多段代码
- (void)groups_semaphore{NSArray *urls1 = @[@"https://www.mi.com",@"https://www.qq.com",@"https://www.sougou.com"];NSArray *urls2 = @[@"https://www.sina.com",@"https://www.baidu.com",@"https://www.jd.com"];NSArray *> *groups = @[urls1,urls2];dispatch_group_t sectionGroup = dispatch_group_create();// 利用信号量来控制请求顺序dispatch_semaphore_t sem = dispatch_semaphore_create(0);for (NSArray *urls in groups) {dispatch_group_t dispatchGroup = dispatch_group_create();for (NSString *urlString in urls) {NSURLSessionDataTask *dataTask = [self dataTaskWithURLString:urlString completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;if (error) {NSLog(@"error:%@",error);}else{NSLog(@"任务:%@-%ld\n请求结束线程:%@",response.URL,httpResponse.statusCode,[NSThread currentThread]);}dispatch_group_leave(dispatchGroup);}];[dataTask resume];dispatch_group_enter(dispatchGroup);}dispatch_group_enter(sectionGroup);// 注意dispatch_queue_t 不能和dispatch_semaphore_wait在同一线程,不然会造成线程死锁dispatch_group_notify(dispatchGroup, dispatch_get_global_queue(0, 0), ^{NSLog(@"组任务执行完毕,返回主线程进行操作");dispatch_group_leave(sectionGroup);dispatch_semaphore_signal(sem);});NSLog(@"...");dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);}dispatch_group_notify(sectionGroup, dispatch_get_main_queue(), ^{NSLog(@"多组任务都完成了...");});}

