如何解决结果由block返回情况下的同步问题

时间:2022-11-04 07:47:36
开发中经常会遇到一种简单的同步问题:
系统在获取资源时,采用了block写法,外部逻辑需要的结果是在block回调中返回的

举个例子:
请求获取通讯录权限的系统弹窗

调用系统方法请求通讯录权限:

ABAddressBookRequestAccessWithCompletion(addressBook,^(bool granted,CFErrorRef error))

外部需要操作通讯录实例addressBook,但这个实例是在block中返回的,如果不加同步判断的话,如果下一步执行了:

ABAddressBookGetPersonCount(addressBook)

则有可能会crash,原因是 addressBook 无效,为什么无效呢?是因为block中的代码块并不是同步执行的,调用ABAddressBookGetPersonCount(addressBook)的时候有可能根本就没有执行到block,所以addressBook此时并未被正确创建并初始化

如何解决这个问题?
采用如下写法,用信号量解决
dispatch_semaphore_t sema =dispatch_semaphore_create(0);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
    dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema,DISPATCH_TIME_FOREVER);

原理:
先设置一个信号量,信号量为0;
执行block
当前线程调用完block,没有执行到block里面之前,都等待(wait在信号量为0的时候只会等待,在信号量>0的时候才会减一继续执行)
block执行完毕,最后执行signal,将信号量+1
wait到信号量>0,将信号量减一退出,继续执行下面的逻辑

如此一来,就保证了addressBook真正使用之前已被正确创建并初始化,后面就可以放心的使用addressBook