除非与NSRunLoop一起使用,否则dispatch_group_wait没有按预期运行?

时间:2012-10-11 04:43:32

标签: objective-c grand-central-dispatch

我正在试图找出导致以下行为的特殊属性NSRunLoop。

首先,我要做的是等待CLGeocoder在继续之前完成执行。如果我使用完成块,代码将如下所示:

if (/* loc has valid coordinates */)
    [gc reverseGeocodeLocation:loc completionHandler:^(NSArray *placemarks, NSError error){
        //do things
        [gc reverseGeocodeLocation:newloc completionHandler:^(NSArray *placemarks, NSError error){
            //do more things with newloc
            // MOVE TO NEXT VIEW
        }
     }
else if (/*still have to check for newloc*/)
    [gc reverseGeocodeLocation:loc completionHandler:^(NSArray *placemarks, NSError error){
        //do things
        //MOVE TO NEXT VIEW

不幸的是,这些块的//do things部分是冗长的,如果我在自己的函数中嵌套CLGeocoder,它会更清晰,并且在我调用它两次后移动到下一个视图。

我找到了一种迫使等待的方法,感谢答案:Waiting for CLGeocoder to finish on concurrent enumeration

所以新方法有效,但我不知道为什么它有效。这是代码:

dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);

[gc reverseGeocodeLocation:loc completionHandler:^(NSArray *placemarks, NSError *error){
    //do things
    dispatch_group_leave(group);
}

//this is the confusing part!
while(dispatch_group_wait(group,DISPATCH_TIME_NOW)){
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                             beforeDate:[NSDate dateWithTimeIntervalSinceNow:1.0f]];
}
dispatch_release(group);

奇怪的是,如果我在没有while循环的情况下执行以下操作,应用程序会挂起:

dispatch_group_wait(group,DISPATCH_TIME_FOREVER);

鉴于我到目前为止所读到的一切,这应该有用,对吗?


更令人困惑的是,NSRunLoop在while循环中是必需的。如果我完全删除它,留下一个空的while循环,循环将无休止地重复。像这样:

//this is the confusing part!
while(dispatch_group_wait(group,DISPATCH_TIME_NOW)){
    //without NSRunLoop, this just goes on forever
}

NSRunLoop做了什么让while循环成功结束?

1 个答案:

答案 0 :(得分:2)

CLGeocoder文档说它在主线程上运行完成处理程序块。我推断你正在主线程上运行你的等待或你的while(dispatch_group_wait(...))循环。如果阻塞主线程,则主线程无法运行完成块。

通过在while循环中调用runMode:beforeDate:,您可以为运行循环提供运行完成块的机会。

你在做什么很糟糕。你不应该阻止主线程,你应该尽量避免递归地运行一个运行循环(因为,正如你所发现的,它是令人困惑的)。 CLGeocoder允许您提供完成块的原因是您可以将其设置为然后返回主运行循环。稍后,当CLGeocoder运行完成块时,您可以以任何您需要的方式使用结果。