在我的应用程序中,当用户按下按钮时,我启动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];
寻求帮助
答案 0 :(得分: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
的{{1}} documentation所说,您无法保证完成操作会发生什么线程:
无法保证完成块的确切执行上下文,但通常是辅助线程。因此,您不应该使用此块来执行任何需要非常特定的执行上下文的工作。相反,您应该将该工作分流到应用程序的主线程或能够执行此操作的特定线程。 ...
UI更新必须在主队列上进行,因此如果您的完成块想要执行UI更新,则必须将它们显式添加到主队列。
答案 1 :(得分: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...
});
}];