【问题标题】:Is calling -[NSRunLoop runUntilDate:] a good idea?调用 -[NSRunLoop runUntilDate:] 是个好主意吗?
【发布时间】:2023-03-26 03:55:01
【问题描述】:

打电话给-[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]];
}

再次,这似乎工作正常。使用这种方法是否有任何潜在问题?

【问题讨论】:

    标签: iphone ipad ios asihttprequest nsrunloop


    【解决方案1】:

    显示某种微调器并将其拆除以响应来自网络代码的异步完成事件不是更好吗?喜欢:

    [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];
    

    我认为这比使用运行循环更好。但可能您已经知道这一点,只是想知道 runloop 解决方案有哪些确切的缺点?


    如果你想阻塞直到值准备好,你可以使用信号量:

    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);
    

    【讨论】:

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

    您必须确保不要从您正在调用的运行循环可能调用的任何方法中执行此操作,除非重叠的调用树是完全可重入的。

    Cocoa Touch UI 代码没有记录为可重入(事实上,Apple DTS 有警告/提示不是这样),因此如果您的获取数据处理程序可以以任何方式由 UI 方法调用(或其他可在 UI 运行循环中调用的不可重入代码),不建议从其内部调用 UI 运行循环。

    【讨论】:

    • 因此,在这种情况下,听起来这种方法是安全的,因为在它忙于下载数据时没有其他东西可以调用此属性。但是如果有这样一种情况,用户可以在它忙的时候点击一个按钮并再次调用该属性,那么它会爆炸吗?很高兴知道。
    • 此属性是否被任何 UI 方法或委托直接或间接使用?如果是这样,这仍然是一个大问题。
    • 我敢肯定,当应用程序在 UI 呈现给用户之前最初加载时,它只会点击此代码一次。之后,数据将在那里,它将使用局部变量。如果由于某种原因无法下载数据,它会向用户显示模式警报,并且在下载成功之前他们无法进入应用程序。
    • 重入是什么意思?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-29
    • 1970-01-01
    • 2013-03-09
    相关资源
    最近更新 更多