Ios 设置UIImage和UITextField后,UIView未正确更新
我有一些从服务器获取的数据,然后显示在UIViewController类中。要做到这一点,我有两门课。UIViewController和另一个名为ServerCommunicator的控制器。UIViewController是ServerCommunicator类的委托。serverCommunicator如下所示:Ios 设置UIImage和UITextField后,UIView未正确更新,ios,objective-c,xcode,uiview,uiviewcontroller,Ios,Objective C,Xcode,Uiview,Uiviewcontroller,我有一些从服务器获取的数据,然后显示在UIViewController类中。要做到这一点,我有两门课。UIViewController和另一个名为ServerCommunicator的控制器。UIViewController是ServerCommunicator类的委托。serverCommunicator如下所示: - (void)fetchServerData:(NSString *) serverAddress{ NSURL *url = [[NSURL alloc] ini
- (void)fetchServerData:(NSString *) serverAddress{
NSURL *url = [[NSURL alloc] initWithString:serverAddress];
[NSURLConnection sendAsynchronousRequest:[[NSURLRequest alloc] initWithURL:url] queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error) {
[self.delegate fetchingSongsFailedWithError:error];
} else {
[self.delegate receivedSongsJSON:data];
}
}];
}
UIViewController分配serverCommunicator,将自身设置为委托,然后发出获取请求
- (void)viewDidLoad {
[super viewDidLoad];
self.songServerCommunicator = [[serverCommunicator alloc] init];
self.songServerCommunicator.delegate = self;
[self.songServerCommunicator fetchServerData:<some_server_ip>];
}
我的问题是,当我显示委托方法中接收的数据时,它不会立即反映在UI中。这是非常奇怪的,有时它会在20秒后单独显示,其他时候需要一分钟。我不知道发生了什么事。我知道数据是立即获取的,因为记录的消息是在UIView更新之前打印出来的
谢谢你在这方面的帮助 更新UI时,请确保您处于主线程上方法receivedSongsJSON()是从[NSURLConnection sendAsynchronousRequest]的回调调用的,我认为该回调是从后台线程调用的 即使在UIViewController中声明了receivedSongsJSON()方法,如果从一个线程调用它,它也将在后台线程中执行
正如@robdashnash所指出的,确保从主线程调用所有UI更新代码。如果您不确定如何做到这一点,请查看Grand Central Dispatch(GCD)的文档。其他人已经指出了问题,但他们没有提供具体代码中的解决方案。这是编码的解决方案:
- (void)fetchServerData:(NSString *) serverAddress{
NSURL *url = [[NSURL alloc] initWithString:serverAddress];
[NSURLConnection sendAsynchronousRequest:[[NSURLRequest alloc] initWithURL:url] queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
dispatch_async(
dispatch_get_main_queue(),
^void {
if (error) {
[self.delegate fetchingSongsFailedWithError:error];
} else {
[self.delegate receivedSongsJSON:data];
}
}
);
}];
}
您必须了解如何在iOS中工作。GCD是多线程的抽象层
运行UI的主队列是一个串行队列。这意味着不能同时运行两个代码块。如果在主队列上执行长时间的网络查询,则用户体验会很差,因为这会阻止任何UI代码运行。这将使应用程序在用户面前看起来像被冻结了一样
为了解决冻结UI的问题,iOS为您提供了其他队列来执行工作,而不会阻塞主队列。iOS提供了创建您自己的自定义队列或使用预先创建的全局并发队列的方法。我们不知道NSURLConnection使用的队列,因为我们没有Cocoa源代码。但我们知道的是,NSURLConnection肯定没有使用主队列,因为UI在从服务器抓取数据时没有冻结
由于NSURLConnection运行的线程与主队列(UI)运行的线程不同,因此您不能在任何随机时间更新UI。这是多线程程序的常见问题。当多个线程访问同一代码块时,指令可能会交错,两个块都会得到意外的结果。您遇到的一个意外结果是UI最终更新延迟了20秒。为了防止交错,您需要在同一线程上运行所有UI代码。您可以通过将UI更新代码排队到主队列的末尾来完成此操作。编辑您的代码以添加在UI中设置值的方式。请告诉我们您的代码在哪里设置这些值。问题就如JOJO,abdullah和rob在下面指出的那样。你这个摇滚人!!非常感谢你的解释,欢迎你。请接受为您提供正确信息的答案以解决此问题。我认为@JoJo的答案是最好的。
- (void)fetchServerData:(NSString *) serverAddress{
NSURL *url = [[NSURL alloc] initWithString:serverAddress];
[NSURLConnection sendAsynchronousRequest:[[NSURLRequest alloc] initWithURL:url] queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
dispatch_async(
dispatch_get_main_queue(),
^void {
if (error) {
[self.delegate fetchingSongsFailedWithError:error];
} else {
[self.delegate receivedSongsJSON:data];
}
}
);
}];
}