调用-[NSRunLoop runUntilDate:]是个好主意吗?

9
通常调用-[NSRunLoop runUntilDate:]是个好主意吗?它似乎没有任何问题,但是让运行循环在运行循环内部运行让我感到紧张。
更多信息:
我现在有一个从REST服务中获取数据的项目。其中一个关键信息是获取具有有效数据的日期范围。这只是一小部分数据,只需要获取一次,因此我决定最好的处理方法是当本地变量为nil时,使属性下载数据。我正在使用ASIHTTPRequestASINetworkQueue,因此默认情况下所有内容都是异步的。为了使其工作,该属性在数据下载和处理完成之前不能返回。以下是我的代码概述,变量名称已更改以保护无辜者:
__block BOOL isWorking = YES;
__block ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:/*actual URL*/] autorelease];
[request setCompletionBlock:^{
    // set local variable
    isWorking = NO;
}];
[request setFailedBlock:^{
    // show alert to user
    isWorking = NO;
}];
[queue addOperation:request];

while (isWorking) {
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
}

再次测试,看起来这个方法运行良好。使用这种方法可能会有哪些潜在问题吗?

2个回答

4
"是否最好显示某种旋转图标,并在网络代码异步完成事件响应时将其撤下?例如:"
[self displayLoadingSpinner];
[request setCompletionBlock:^{
    [self handleSuccess];
    dispatch_async(dispatch_get_main_queue(), ^{
        [self hideLoadingSpinner];
    }];
}];
[request setFailedBlock:^{
    [self handleFailure];
    dispatch_async(dispatch_get_main_queue(), ^{
        [self hideLoadingSpinner];
    }];
}];
[queue addOperation:request];

我认为这比对运行循环进行修改更好。但是可能你已经知道了这一点,只是想知道在运行循环解决方案中确切的缺点是什么?
如果您想阻塞直到值准备就绪,可以使用信号量:
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
[request setCompletionBlock:^{
    dispatch_semaphore_signal(sem);
}];
[queue addOperation:request];

dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
dispatch_release(sem);

如果委托/回调方法是可行的,这就是我会采取的方法。在这种情况下,我需要在从属性返回之前设置值,否则应用程序将继续使用错误的数据。我可以重构代码以使设计模式起作用。这个问题实际上是想找出是否有任何意想不到的问题,我还没有看到。 - Jose Ibanez
信号量方法不会阻塞主线程吗?那样不会防止块执行吗? - Jose Ibanez
这取决于你使用的HTTP库是如何实现的。是的,主线程将会阻塞,因此如果库使用主线程,你就不能使用信号量。 - zoul
是的,看起来 ASIHTTPRequest 从主线程调用所有块。 - Jose Ibanez
在这种情况下,我的回答变得越来越无用了 :-) - zoul

3

请务必确保不要从可能被调用的运行循环中执行此操作,除非重叠的调用树是完全可重入的。

Cocoa Touch UI 代码没有记录为可重入(实际上,苹果 DTS 有警告/提示表明它不是),因此,如果您的获取数据处理程序可以以任何方式被 UI 方法(或其他非可重入代码,可能在 UI 运行循环中调用)调用,则不建议从其中调用 UI 运行循环。


所以在这种情况下,听起来这种方法是安全的,因为在下载数据时没有其他东西可以调用此属性。但是如果存在一种情况,用户在它忙碌的时候按下按钮并再次调用该属性,那么程序会崩溃?好的,知道了。 - Jose Ibanez
这个属性是否被任何UI方法或委托直接或间接使用?如果是,那仍然是一个大问题。 - hotpaw2
我确信它只会在应用程序最初加载时命中此代码一次,甚至在 UI 显示给用户之前。之后,数据将会在那里并且它将使用本地变量。如果由于某种原因无法下载数据,则会向用户显示模态警报,直到成功下载为止才能进入应用程序。 - Jose Ibanez
什么是可重入? - airpaulg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接