美文网首页iOS开发文集iOS Developer移动开发
如何“优雅”使用GCD Semaphore

如何“优雅”使用GCD Semaphore

作者: la0fu | 来源:发表于2016-10-20 17:15 被阅读64次

    信号量(Semaphore)在GCD编程中是一个重要的概念,也是一个容易被忽略的概念。如果使用得当,可以巧妙地解决app开发中一些“头疼”的问题。本文会基于一个常见的场景来探讨如何合理使用信号量。

    业务场景:

    app实现了实现直播功能,用户点击直播按钮前,app会要求获取用户的麦克风和相机权限,如果用户同意了这两个权限,则进入直播页面;否则,app弹出alert窗口提示用户去系统设置里打开对应的权限。

    面对这个“简单”的需求,作为写过很多次权限获取的iOS程序员,自然而然地写了如下代码(此处采用本人写的权限框架来获取,点此了解):

    初次实现

    __block BOOL micGranted = NO;
    __block BOOL cameraGranted = NO;
        
    //获取麦克风权限
    [[LFPermissionMgr sharedInstance] accessMic:^(BOOL granted) {
        micGranted = granted;
        if (granted) {
            NSLog(@"mic granted");
        } else {
            NSLog(@"mic not granted");
        }
    }];
    
    //获取摄像头权限    
    [[LFPermissionMgr sharedInstance] accessCamera:^(BOOL granted) {
        cameraGranted = granted;
        if (granted) {
            NSLog(@"camera granted");
        } else {
            NSLog(@"camera not granted");
        }
    }];
        
    if (micGranted && cameraGranted) {
        NSLog(@"start live succeed");
        [self startLiveVC];      //进入直播页面
    } else {
        NSLog(@"start live failed");
        [self showAlertView];    //弹出alert,提示用户打开系统权限
    }
    
    

    然而,当app运行,你发现系统权限窗口是弹了,但是console直接输出了“start live failed”,说明程序直接进入到了NSLog(@"start live failed");,然而此时我们还没有对权限弹出窗口做权限选择。这种写法有问题。

    为什么会这样?因为系统提供的权限获取函数是异步(asynchronous)执行的,还没等用户操作,就直接往下执行了。由于micGrantedcameraGranted都为NO,自然而然,进入了else的逻辑。但是我们的需求是只有当用户操作了前面的两个权限获取后,我们才判断是否进入直播页面还是提示用户打开系统权限。这个问题可以简化成:如何等待异步block执行结束,根据处理结果,再执行其它代码?

    这时候信号量就可以派上用场了。我们可以通过dispatch_semaphore_t获取信号量,然后通过对信号量的操作,完美地解决这个问题。

    对于单个block执行的一般用法

    dispatch_semaphore_t sem = dispatch_semaphore_create(0);
    
    [self methodWithABlock:^(id result){
        //put code here
        dispatch_semaphore_signal(sem);
    }];
    
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
    
    

    对于多个block执行的一般用法

    dispatch_semaphore_t sem = dispatch_semaphore_create(0);
    
    [self methodWithABlock:^(id result){
        //put code here
        dispatch_semaphore_signal(sem);
    }];
    
    [self methodWithABlock:^(id result){
        //put code here
        dispatch_semaphore_signal(sem);
    }];
    
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
    

    所以针对我们的需求,代码作如下修改

    采用Semaphore的实现

    __block BOOL micGranted = NO;
    __block BOOL cameraGranted = NO;
        
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
    //获取麦克风权限    
    [[LFPermissionMgr sharedInstance] accessMic:^(BOOL granted) {
        micGranted = granted;
        if (granted) {
            NSLog(@"mic granted");
        } else {
            NSLog(@"mic not granted");
        }
        dispatch_semaphore_signal(semaphore);
    }];
    
    //获取摄像头权限 
    [[LFPermissionMgr sharedInstance] accessCamera:^(BOOL granted) {
        cameraGranted = granted;
        if (granted) {
            NSLog(@"camera granted");
        } else {
            NSLog(@"camera not granted");
        }
        dispatch_semaphore_signal(semaphore);
    }];
        
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        
    if (micGranted && cameraGranted) {
        [self startLiveVC];
    } else {
        [self showAlertView];
    }
    

    编译运行,会发现app执行和我们预想的一致:先弹出麦克风权限获取窗口,然后再弹出摄像头权限获取窗口,根据我们的操作,分别执行打开直播页面或者弹出权限alert窗口。

    结论

    掌握信号量的使用是一个iOS开发者的基本功。本文探讨了在一个具体业务场景下对信号量的使用方法,限于篇幅,没有讨论具体的理论概念。信号量是计算机科学的一个基本概念,不仅在iOS开发中,在各种语言开发中一般都会涉及。有兴趣的同学可以进一步了解相关使用方法,根据自身业务需求,举一反三。

    下载代码

    相关文章

      网友评论

        本文标题:如何“优雅”使用GCD Semaphore

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