信号量在block回调中的运用

背景

实际开发过程中经常会在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);要放在业务逻辑的后面

参考链接

另外

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 锁是一种同步机制,用于多线程环境中对资源访问的限制iOS中常见锁的性能对比图(摘自:ibireme): iOS锁的...
    LiLS阅读 5,449评论 0 6
  • 本文为转载资料,原文地址: http://www.jianshu.com/p/02821f9d7777 一、信号量...
    一曰就是一天阅读 4,954评论 0 3
  • “法于阴阳,和于术数,饮食有节,起居有常,不作妄劳。” ——《黄帝·内经》 所谓饮食有节 是指饮食要有节制 不能随...
    三象2017阅读 3,474评论 0 1
  • 今天的晨读材料《聪明人的问题解决指南,超有用》来自唐纳德的《你的灯还亮着吗?》,文中告诉我们快速解决问题的本质在于...
    婷婷姐_2019阅读 2,823评论 0 1
  • 记录此刻心情。也许多年后再来看这日记或者抱怨一般的文字,或许会觉得当年的自己幼稚,又或许委屈。 3月份的时候从万科...
    二喵的篮子阅读 1,688评论 0 0

友情链接更多精彩内容