美文网首页
信号量在block回调中的运用

信号量在block回调中的运用

作者: 12345qwert | 来源:发表于2018-11-02 16:52 被阅读17次

    背景

    实际开发过程中经常会在block回调中拿到数据后做进一步处理,业务复杂的可能会将回调一层层套下去,比如伪代码会这样:

    A handleWithCompletionBlock:^{
        B handleWithCompletionBlock:^{
            C handleWithCompletionBlock:^{
            }
        }
    }
    

    这样的情景很多,比如三个网络请求,下一个网络请求需要用到上一个回调的数据作为请求参数,但是如果直接这样嵌套的这样写,会有一些弊端:比如,(1)代码可读性较差(2)另外如果回调层数多起来的话(或者说压根就不知道有多少层),这样的写法也不现实。

    解决方案

    碰到类似的情况,我们可以用信号量来解决。信号量主要有3个函数,分别是:

    • 创建信号量,参数:信号量的初值,如果小于0则会返回NULL
      dispatch_semaphore_create(信号量值)

    • 等待降低信号量
      dispatch_semaphore_wait(信号量,等待时间)

    • 提高信号量
      dispatch_semaphore_signal(信号量)

    注意,正常的使用顺序是先降低然后再提高,这两个函数通常成对使用。

    简单的例子

    我们模拟下场景,用如下3个print方法,3个print方法都加在全局队列里,异步开启各自的线程执行代码。

    - (void)print1WithCompletion:(void(^)(NSString *previousPrint))completion {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSString *log = @"------> print 1";
            completion(log);
        });
    }
    - (void)print2WithPrint1Info:(NSString *)print1Info completion:(void(^)(NSString *previousPrint))completion {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSString *log = [NSString stringWithFormat:@"%@------> print 2",print1Info];
            completion(log);
        });
    }
    - (void)print3WithPrint2Info:(NSString *)print2Info completion:(void(^)(void))completion {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSString *log = [NSString stringWithFormat:@"%@------> print 3",print2Info];
            NSLog(@"%@",log);
            completion();
        });
    }
    
    @property (nonatomic, strong) dispatch_semaphore_t semaphore;
    self.semaphore = dispatch_semaphore_create(1);
    

    利用信号量处理

    print2拿到print1的信息,print3拿到print2的信息,最终print3输出全部的信息,通过这个场景,我们来模拟3个网络请求的嵌套。接下来我们用信号量来处理。

    - (void)startPrintBySemaphore {
        dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
        __block NSString *print1Info = nil;
        [self print1WithCompletion:^(NSString *previousPrint) {
            print1Info = previousPrint;
            dispatch_semaphore_signal(self.semaphore);
        }];
        
        dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
        __block NSString *print2Info = nil;
        [self print2WithPrint1Info:print1Info completion:^(NSString *previousPrint) {
            print2Info = previousPrint;
            dispatch_semaphore_signal(self.semaphore);
        }];
        
        dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
        [self print3WithPrint2Info:print2Info completion:^{
            dispatch_semaphore_signal(self.semaphore);
        }];
    }
    

    注意点

    • 这里设置了dispatch_semaphore_create(1),这个根据自己的实际需求定
    • 调用了dispatch_semaphore_wait就会使信号量-1,只要信号量>=0都能正常执行代码,不会阻塞进程
    • dispatch_semaphore_signal会使信号量+1,可以理解为:我执行好了,通道恢复正常增加了1条。(这里总共的通道就是1条)
    • dispatch_semaphore_signal(self.semaphore);要放在业务逻辑的后面

    参考链接

    另外

    相关文章

      网友评论

          本文标题:信号量在block回调中的运用

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