如果SDKPlatform
正在将其完成块分派回主队列,那么阻止主线程直到完成块被调用的方法肯定会死锁,并且您无法做到这一点。但是,这种信号量方法阻止主线程,所以您可以使异步方法像同步方法一样行事,无论如何,这是一种不可取的方法。实际上你应该拥抱异步模式,并在你自己的代码中使用完成块技术。
该链接How do I wait for an asynchronously dispatched block to finish?说明了如何使用信号量使异步任务同步运行。可悲的是,这种技术被误用于报警频率。具体而言,在这种情况下,信号量不是您场景中的适当模式,因为信号量模式会阻止主线程,这是我们在应用程序中永远不应该做的事情。
作为背景,信号量技术在其他线程中讨论的场景中很好,因为它是一个非常不同的技术问题。它被用于测试框架的特殊情况,而不是应用程序,以及(a)测试本身必须在主线程上发生的情况; (b)为使测试框架起作用,它必须阻塞主线程,直到异步任务完成。此外,它也适用于该测试场景,因为完成块不会在主队列上发生,从而避免了您遇到的死锁问题。
这三个条件都不适用于您的情况。在你的情况下使用信号量技术是不可取的。
所以,让我们退后一步,看看你的问题。我假设你有一些方法,看起来像:
- (BOOL) login
{
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
__block BOOL _isLogined;
__block BOOL _isCallback = NO;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue,^{
//Put your heavy code here it will not block the user interface
[[SDKPlatform defaultPlatform] SDKIsLogined:^(BOOL isLogined){
_isLogined = isLogined;
_isCallback = YES;
dispatch_semaphore_signal(sema);
}];
});
while (!_isCallback) {
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
}
return _isLogined;
}
即使你没有你的死锁问题,这仍然是错误的花样。你可能想要的是一样的东西:
- (void)loginWithCompletionHandler:(void (^)(BOOL isLoggedIn))completionHandler
{
[[SDKPlatform defaultPlatform] SDKIsLogined:^(BOOL isLoggedIn){
if (completionHandler) {
completionHandler(isLoggedIn);
}
}];
}
注意,这个功能有一个void
返回类型,而是isLoggedIn
状态由完成块返回(并应完成区块内仅使用,就像这样:
[self loginWithCompletionHandler:^(BOOL isLoggedIn) {
// feel free to use isLoggedIn here
}];
// don't try to use isLoggedIn here
来源
2014-09-29 19:56:13
Rob
除非我误解了一些与信号灯的方法等是完全不正确的,埃里克。你要做的是:(1)运行的代码(2)完成后,通知主线程,然后你可以做接下来的事情,这是绝对平常的,下面的例子! – Fattie 2014-09-29 06:28:37
你需要增加你的信号计数“1”(使用“1”代替它的创建时间为0)。创建没有空间访问共享资源的信号量会在调用dispatch_semaphore_wait时导致死锁。 – user298261 2015-06-04 20:32:42