美文网首页iOS开发笔记iOS Developer
iOS开发技巧: 将异步方法封装成同步方法

iOS开发技巧: 将异步方法封装成同步方法

作者: 不上火喝纯净水 | 来源:发表于2017-08-17 23:45 被阅读3243次
    在开发中我们经常会遇到异步方法,在设计程序逻辑的时候有些操作依赖于异步的回调结果,有时候我们不得不把一个原本内聚的逻辑通过代理或者回调的方式打散开来,这样作它打乱了我们代码顺序执行的流程。如果这个方法是同步的就好了

    本篇文章会介绍针如何将异步API或者接口封装成同步方法(使用GCD的方式)

    方法调用者希望调用的是一个同步返回的方法,而不是以callback形式携带返回值的方法。
    // 同步方法
    - (NSInteger)methodSync {
        __block NSInteger result = 0;
        [self methodAsync:^(NSInteger value) {
            result = value;
        }];
       // 如果result同步返回就好了
        return result;
    }
    
    // 异步方法
    - (void)methodAsync:(void(^)(NSInteger result))callBack {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"methodAsync 异步开始");
            sleep(2);
            NSLog(@"methodAsync 异步结束");
            if (callBack) {
                callBack(5);
            }
        });
    }
    

    GCD是我们平常开发中使用频率最高的多线程方式,对于处理上述问题当然也是不在话下

    • 方式一:使用派发组dispatch_group

    dispatch_group可以很方便的管理多个派发任务,并在任务结束时候可以得到回调通知,或者可以一直阻塞线程直到派发组内的所有派发任务都完成

    - (NSInteger)methodSync {
        NSLog(@"methodSync 开始");
        __block NSInteger result = 0;
        dispatch_group_t group = dispatch_group_create();
        dispatch_group_enter(group);
        [self methodAsync:^(NSInteger value) {
            result = value;
            dispatch_group_leave(group);
        }];
        dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
        NSLog(@"methodSync 结束 result:%ld", (long)result);
        return result;
    }
    
    • 方式二(推荐):使用信号量dispatch_semaphore

    dispatch_semaphore通常是用来多线程执行多个并发任务时通过信号量的方式对并发执行数量的限制。当信号量不够(=0)的时候当前调用线程将被阻塞,所以我们可以通过模拟信号量不够的情况来阻塞同步方法的返回,直到方法内部的异步回调之后;

    - (NSInteger)methodSync {
        NSLog(@"methodSync 开始");
        __block NSInteger result = 0;
        dispatch_semaphore_t sema = dispatch_semaphore_create(0);
        [self methodAsync:^(NSInteger value) {
            result = value;
            dispatch_semaphore_signal(sema);
        }];
       // 这里本来同步方法会立即返回,但信号量=0使得线程阻塞
       // 当异步方法回调之后,发送信号,信号量变为1,这里的阻塞将被解除,从而返回正确的结果
        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
        NSLog(@"methodSync 结束 result:%ld", (long)result);
        return result;
    }
    

    当然是用操作队列OperationQueue也是可以实现这个需求,但会更麻烦一些,我认为直接使用GCD的方式是最为轻量的,推荐大家在实践中使用

    相关文章

      网友评论

        本文标题:iOS开发技巧: 将异步方法封装成同步方法

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