美文网首页程序员
GCD实现异步任务的同步处理

GCD实现异步任务的同步处理

作者: coderLZ | 来源:发表于2017-02-24 15:43 被阅读0次
前言

标题可能有点词不达意了,但内容应该是大部分开发都会遇到的问题。面试时或开发中可能会遇到:有A,B,C,D四个任务,如何实现A,B,C都执行完成之后再执行D呢?应该直接能想到的是用dispatch_groupdispatch_group_notify来实现。没错!那如果A,B,C三个任务都是网络请求的情况会如何呢?很明显网络请求都是异步执行,按原来的写法必然达不到目的。接下来我会以一个页面有多个网络请求,全部网络数据加载完成之后再刷新页面为场景介绍两种常用的方法来解决此问题。

方法一、利用 dispatch_semaphore信号量

dispatch_semaphore信号量为基于计数器的一种多线程同步机制。
有dispatch_semaphore_create// 创建信号量,参数:信号量的初值,如果小于0则会返回NULL
dispatch_semaphore_signal// 提高信号量, 使信号量加1
dispatch_semaphore_wait//等待降低信号量,接收一个信号和时间值(多为DISPATCH_TIME_FOREVER); 若信号的信号量为0,则会阻塞当前线程,直到信号量大于0或者经过输入的时间值; 若信号量大于0,则会使信号量减1并返回,程序继续住下执行
三个方法。

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
   [super touchesBegan:touches withEvent:event];
    
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //请求1
       [self HttpRequestWith:@"https://api.douban.com/v2/movie/in_theaters?start=0&count=3" andTag:@"请求1+"];
      
    });
   
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
      //请求2
        [self HttpRequestWith:@"https://api.douban.com/v2/movie/top250?start=0&count=3" andTag:@"请求2+"];
    });

    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //请求3
        [self HttpRequestWith:@"https://api.douban.com/v2/movie/coming_soon?start=0&count=3"andTag:@"请求3+"];
    });

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        //刷新UI
        NSLog(@"数据加载完之后回主线程刷新界面");
    });

}

将访问网络部分作为公共方法

-(void)HttpRequestWith:(NSString *)url andTag:(NSString *)tag
{
    //设置信号量并设置计数默认为0
    dispatch_semaphore_t sema =dispatch_semaphore_create(0);
    [[LZNetwork sharedNetwork]GET:url parameters:nil progress:^(NSProgress *progress) {
        
    } success:^(NSURLSessionDataTask *task, id responseObject) {
        //计数+1
        dispatch_semaphore_signal(sema);
        NSArray *dataArr=[NSArray arrayWithArray:responseObject[@"subjects"]];
        [dataArr enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            NSLog(@"%@%@",tag,obj[@"title"]);
        }];
    } failure:^(NSURLSessionDataTask *task, NSError *error) {
        //计数+1
        dispatch_semaphore_signal(sema);
    }];
    //计数为0时等待
    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);


}

方法二、利用dispatch_group_enter ();dispatch_group_leave ();

首页将 group设置为全局变量。

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [super touchesBegan:touches withEvent:event];
    
    group = dispatch_group_create();
    //请求1
    dispatch_group_enter(group);
   
    [self HttpRequestWith:@"https://api.douban.com/v2/movie/in_theaters?start=0&count=3" andTag:@"请求1+"];
    
     //请求2
    dispatch_group_enter(group);
    
    [self HttpRequestWith:@"https://api.douban.com/v2/movie/top250?start=0&count=3" andTag:@"请求2+"];
    
    //请求3
    dispatch_group_enter(group);
    
    [self HttpRequestWith:@"https://api.douban.com/v2/movie/coming_soon?start=0&count=3"andTag:@"请求3+"];
    
    dispatch_group_notify(group,dispatch_get_main_queue(), ^{
        //刷新UI
        NSLog(@"数据加载完之后回主线程刷新界面");
    });
    
    
   }

网络公共方法中:

-(void)HttpRequestWith:(NSString *)url andTag:(NSString *)tag
{
    [[LZNetwork sharedNetwork]GET:url parameters:nil progress:^(NSProgress *progress) {
        
    } success:^(NSURLSessionDataTask *task, id responseObject) {
        
        NSArray *dataArr=[NSArray arrayWithArray:responseObject[@"subjects"]];
        [dataArr enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            NSLog(@"%@%@",tag,obj[@"title"]);
        }];
        dispatch_group_leave(group);
    } failure:^(NSURLSessionDataTask *task, NSError *error) {
        //计数+1
        dispatch_group_leave(group);
        
    }];

注:dispatch_group_enter ()和dispatch_group_leave ()成对出现

两种方法输出结果
输出结果为

2017-02-24 15:11:06.033 GCD-group[1842:139777] 请求1+生化危机:终章
2017-02-24 15:11:06.033 GCD-group[1842:139777] 请求1+刺客信条
2017-02-24 15:11:06.034 GCD-group[1842:139777] 请求1+三缺一
2017-02-24 15:11:06.447 GCD-group[1842:139777] 请求2+肖申克的救赎
2017-02-24 15:11:06.447 GCD-group[1842:139777] 请求2+这个杀手不太冷
2017-02-24 15:11:06.448 GCD-group[1842:139777] 请求2+霸王别姬
2017-02-24 15:11:07.573 GCD-group[1842:139777] 请求3+金刚狼3:殊死一战
2017-02-24 15:11:07.573 GCD-group[1842:139777] 请求3+一条狗的使命
2017-02-24 15:11:07.574 GCD-group[1842:139777] 请求3+乐高蝙蝠侠大电影
2017-02-24 15:11:07.574 GCD-group[1842:139777] 数据加载完之后回主线程刷新界面

注:三个请求任务之间是异步,所以它们之间执行顺序不定。

结语

希望以上知识点对你有所帮助,也希望多多指教。

相关文章

  • GCD实现异步任务的同步处理

    前言 标题可能有点词不达意了,但内容应该是大部分开发都会遇到的问题。面试时或开发中可能会遇到:有A,B,C,D四个...

  • OC 线程笔记

    GCD: 创建任务,添加到队列,GCD自动分发任务 同步/异步同步任务,异步任务的区别: 线程是否要等待任务结束,...

  • GCD队列、同步异步

    GCD队列、同步异步 GCD队列、同步异步

  • GCD

    GCD的底层实现 基本理解 重点 并发:同步的话,任务按顺序执行。异步:真正的并发。 同步和异步:能不能开辟一个线...

  • 多线程

    iOS中的几种多线程GCD1、GCD分为任务和队列,任务(同步,异步)队列(串行,并发),同步串行,同步主队列的情...

  • GCD学习总结

    GCD容易混淆的概念 任务,同步,异步 ,串行队列,并发队列 任务就是要做的事情 同步和异步是用来执行任务的 串行...

  • iOS之GCD学习心得

    1.GCD简介 gcd有两大概念:任务和队列(1) 任务:同步任务和异步任务。同步任务:不会开辟线程,在当前线程执...

  • 06进阶之路-多线程管理

    1. GCD相关 学习链接 GCD 简介 (多核编程管理线程) GCD 任务和队列(同步和异步任务 并发和串行队列...

  • 2019 iOS面试题-----多线程相关之GCD、死锁、dis

    GCD---同步/异步 ,串行/并发 死锁 GCD任务执行顺序 dispatch_barrier_async di...

  • iOS多线程知识点梳理

    iOS多线程实现方式 pthread NSThread (三种方式创建) GCD 同步&异步针对的主体是任务,以t...

网友评论

    本文标题:GCD实现异步任务的同步处理

    本文链接:https://www.haomeiwen.com/subject/pkjwwttx.html