3

我试图弄清楚 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 循环成功结束?

4

1 回答 1

2

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

通过调用runMode:beforeDate:你的 while 循环,你给了运行循环一个运行完成块的机会。

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

于 2012-10-11T04:50:34.113 回答