核心知识点

  • 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(最常用、最简单)

  1. - (void)dispatch_async_main_queue{
  2. NSURL *url = [NSURL URLWithString:@"https://www.baidu.com"];
  3. NSMutableURLRequest *mRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:3];
  4. NSURLSessionDataTask *dataTask = [[NSURLSession sharedSession] dataTaskWithRequest:mRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
  5. NSLog(@"请求结束线程:%@",[NSThread currentThread]);
  6. // 返回到主线程
  7. dispatch_async(dispatch_get_main_queue(), ^{
  8. NSLog(@"回到主线程:%@\n%@",response.URL,[NSThread currentThread]);
  9. });
  10. }];
  11. [dataTask resume];
  12. }

2. 异步 有序/无序 执行组任务,全部执行完毕返回主线程刷新UI

image.png

  1. /// 组任务无序异步执行
  2. - (void)group_notify{
  3. NSArray *urls = @[@"https://www.sina.com",@"https://www.baidu.com",@"https://www.jd.com"];
  4. dispatch_group_t dispatchGroup = dispatch_group_create();
  5. for (NSString *urlString in urls) {
  6. NSURLSessionDataTask *dataTask = [self dataTaskWithURLString:urlString completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
  7. NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
  8. if (error) {
  9. NSLog(@"error:%@",error);
  10. }else{
  11. NSLog(@"任务:%@-%ld\n请求结束线程:%@",response.URL,httpResponse.statusCode,[NSThread currentThread]);
  12. }
  13. dispatch_group_leave(dispatchGroup);
  14. }];
  15. [dataTask resume];
  16. dispatch_group_enter(dispatchGroup);
  17. }
  18. // 设置组任务的超时时常(需要时可以设置)
  19. dispatch_time_t timeout = dispatch_group_wait(dispatchGroup, dispatch_time(DISPATCH_TIME_NOW, 10 *NSEC_PER_SEC));
  20. if (timeout != 0) {
  21. // 可以在此处取消正在进行的组任务
  22. [[NSURLSession sharedSession] getAllTasksWithCompletionHandler:^(NSArray * _Nonnull tasks) {
  23. [tasks enumerateObjectsUsingBlock:^(__kindof NSURLSessionTask * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  24. if (obj.state != NSURLSessionTaskStateCompleted) {
  25. [obj cancel];
  26. }
  27. }];
  28. }];
  29. NSLog(@"组任务执行超时_%llu",timeout);
  30. }else{
  31. }
  32. dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{
  33. NSLog(@"组任务执行完毕,返回主线程进行操作");
  34. });
  35. }
  36. /// 组任务有序异步执行
  37. - (void)group_notify_semaphore{
  38. NSArray *urls = @[@"https://www.sina.com",@"https://www.baidu.com",@"https://www.jd.com"];
  39. dispatch_group_t dispatchGroup = dispatch_group_create();
  40. // 利用信号量来控制请求顺序
  41. dispatch_semaphore_t sem = dispatch_semaphore_create(0);
  42. for (NSString *urlString in urls) {
  43. NSURLSessionDataTask *dataTask = [self dataTaskWithURLString:urlString completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
  44. NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
  45. if (error) {
  46. NSLog(@"error:%@",error);
  47. }else{
  48. NSLog(@"任务:%@-%ld\n请求结束线程:%@",response.URL,httpResponse.statusCode,[NSThread currentThread]);
  49. }
  50. dispatch_group_leave(dispatchGroup);
  51. // 释放信号量,信号量加1。当信号量>= 0 会执行wait之后的代码
  52. dispatch_semaphore_signal(sem);
  53. }];
  54. [dataTask resume];
  55. dispatch_group_enter(dispatchGroup);
  56. // 等待信号量,信号量减1。当信号量< 0时会阻塞当前线程,根据传入的等待时间决定接下来的操作——如果永久等待将等到信号(signal)才执行下去
  57. dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
  58. }
  59. dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{
  60. NSLog(@"组任务执行完毕,返回主线程进行操作");
  61. });
  62. NSLog(@"...");
  63. }
  64. - (NSURLSessionDataTask *)dataTaskWithURLString:(NSString *)urlString completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler{
  65. NSURL *url = [NSURL URLWithString:urlString];
  66. NSMutableURLRequest *mRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:3];
  67. NSURLSessionDataTask *dataTask = [[NSURLSession sharedSession] dataTaskWithRequest:mRequest completionHandler:completionHandler];
  68. return dataTask;
  69. }

group_notify

image.png

group_notify_semaphore

image.png

3. 异步分组执行多段代码

  1. - (void)groups_semaphore{
  2. NSArray *urls1 = @[@"https://www.mi.com",@"https://www.qq.com",@"https://www.sougou.com"];
  3. NSArray *urls2 = @[@"https://www.sina.com",@"https://www.baidu.com",@"https://www.jd.com"];
  4. NSArray *> *groups = @[
  5. urls1,
  6. urls2
  7. ];
  8. dispatch_group_t sectionGroup = dispatch_group_create();
  9. // 利用信号量来控制请求顺序
  10. dispatch_semaphore_t sem = dispatch_semaphore_create(0);
  11. for (NSArray *urls in groups) {
  12. dispatch_group_t dispatchGroup = dispatch_group_create();
  13. for (NSString *urlString in urls) {
  14. NSURLSessionDataTask *dataTask = [self dataTaskWithURLString:urlString completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
  15. NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
  16. if (error) {
  17. NSLog(@"error:%@",error);
  18. }else{
  19. NSLog(@"任务:%@-%ld\n请求结束线程:%@",response.URL,httpResponse.statusCode,[NSThread currentThread]);
  20. }
  21. dispatch_group_leave(dispatchGroup);
  22. }];
  23. [dataTask resume];
  24. dispatch_group_enter(dispatchGroup);
  25. }
  26. dispatch_group_enter(sectionGroup);
  27. // 注意dispatch_queue_t 不能和dispatch_semaphore_wait在同一线程,不然会造成线程死锁
  28. dispatch_group_notify(dispatchGroup, dispatch_get_global_queue(0, 0), ^{
  29. NSLog(@"组任务执行完毕,返回主线程进行操作");
  30. dispatch_group_leave(sectionGroup);
  31. dispatch_semaphore_signal(sem);
  32. });
  33. NSLog(@"...");
  34. dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
  35. }
  36. dispatch_group_notify(sectionGroup, dispatch_get_main_queue(), ^{
  37. NSLog(@"多组任务都完成了...");
  38. });
  39. }

image.png