2

在我的应用程序中,当用户按下按钮时,我会启动一个 HTTP 异步请求(使用 AFURLConnectionOperation)并在 completionHandler 块中更改 UILabel 的文本。但是,此更改不会在请求结束时发生,而是在大约 2-3 秒后发生。下面是导致此行为的代码片段。

    AFURLConnectionOperation* operation = ...
    [opration setCompletionBlock:^{
         NSLog(@"This text appears immediatly");
         [myLabel setText:@"this one is delayed for 2-3 sec"];
    }];
    [opreation start];

寻求帮助

4

2 回答 2

7

这是尝试从后台队列执行 UI 更新的症状。如果您将该 UI 更新添加回主队列,您的问题将得到解决:

[operation setCompletionBlock:^{
     NSLog(@"This text appears immediately");
     [[NSOperationQueue mainQueue] addOperationWithBlock:^{
         [myLabel setText:@"this should not be delayed for 2-3 sec"];
     }];
}];

正如NSOperation 文档所说,setCompletionBlock您无法保证完成操作将发生在哪个线程:

无法保证完成块的确切执行上下文,但通常是辅助线程。因此,您不应使用此块来执行任何需要非常特定的执行上下文的工作。相反,您应该将该工作分流到应用程序的主线程或能够执行此操作的特定线程。...

UI 更新必须在主队列中进行,因此如果您的完成块想要执行 UI 更新,它必须显式地将它们添加到主队列中。

于 2013-09-09T20:06:26.187 回答
2

AFURLConnectionOperation是 的子类NSOperation

此外,通过查看AFURLConnectionOperation.m,我们可以看到它setCompletionBlock:基本上只是调用了它的超级方法(当然,它也会照顾locking并在完成后很好地设置completionBlock属性nil)。

重要说明AFURLConnectionOperation不会completionBlock为您在主线程上执行。NSOperation也不保证completionBlock在主线程上执行。

但是,用户界面 (UI) 更新必须发生在主线程上(否则可能会发生意想不到的事情)。

要解决此问题,您需要确保您的 UI 更新发生在主线程上。例如,您可以执行以下操作:

[operation setCompletionBlock:^{
    NSLog(@"This text appears immediately");
    dispatch_async(dispatch_get_main_queue(), ^{
            // do your UI updates here...
    });
}];
于 2013-09-09T20:11:38.647 回答