iOS(OC)异步转同步

5,935 阅读2分钟

在开发RuntimeData框架时,发现在有的地方需要用到异步转同步的方法来处理网络数据获取与数据返回,于是研究了一下如何进行异步转同步的方法 找到如下方法: 使用dispatch_semaphore来实现

dispatch_semaphore是GCD来处理同步的一种方式,使用锁的方式实现 其中包含三个函数:

//创建信号量,value>=0
dispatch_semaphore_t
dispatch_semaphore_create(long value);
//等待信号(信号量-1),大于0则继续执行下面的方法
long
dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);
//发送信号(信号量+1)
long
dispatch_semaphore_signal(dispatch_semaphore_t dsema);

使用方法:

- (id)getObject:(NSString *)key {
    dispatch_semaphore_t signal = dispatch_semaphore_create(0);
    
    NSLog(@"start");
    __block id object;
    
    dispatch_queue_global_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        sleep(5);
        object = @YES;
        NSLog(@"async %@", @YES);
        dispatch_semaphore_signal(signal);
    });

    dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER);
    NSLog(@"sync %@", object);
    return object;
}

上段代码输出如下:

2019-02-19 16:24:04.672790+0800 threadTest[11924:352048] start (wait 5s) 2019-02-19 16:24:09.677194+0800 threadTest[11924:352114] async 1 2019-02-19 16:24:09.677636+0800 threadTest[11924:352048] sync 1 2019-02-19 16:24:09.677929+0800 threadTest[11924:352048] 1

在该场景下,使用的wait等待时间为DISPATCH_TIME_FOREVER,这个地方也是碰到的一个坑,因为我不希望永久等待下去,所以我要设置一个超时时间,用于继续处理其他事务,否则锁死在主线程下那就喜闻乐见了,于是我改动此处为:

dispatch_semaphore_wait(signal, dispatch_time(DISPATCH_TIME_NOW, [[self config] waiting] * 1000));

然后发现怎么进不了block……就很奇怪,于是去查文档发现: dispatch_time中的第二个参数,非秒或毫秒计算,而是直接使用纳秒计算,这时候需要把OC中的时间常量出来了:

#define NSEC_PER_SEC 1000000000ull //1000000000纳秒/秒
#define NSEC_PER_MSEC 1000000ull //1000000纳秒/微妙
#define USEC_PER_SEC 1000000ull //1000000微秒/秒
#define NSEC_PER_USEC 1000ull //1000纳秒/微秒

于是将数据乘入:

dispatch_semaphore_wait(signal, dispatch_time(DISPATCH_TIME_NOW, [[self config] waiting] * NSEC_PER_SEC));

可以正常等待和返回数据了~ 收工