我想在NSURLSession的完成块中更新UI。 初始实现没有立即更新UI。它可能在20秒后更新了UI。这是最初的实现。
NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(100, 200, 150, 150)];
label.backgroundColor = [UIColor greenColor];
label.text = jsonDict[@"object_or_array"];
dispatch_async(dispatch_get_main_queue(), ^{
[self.view addSubview:label];
});
}];
[task resume];
我将主队列中label.text = jsonDict[@"object_or_array"]
的位置移动如下。
dispatch_async(dispatch_get_main_queue(), ^{
label.text = jsonDict[@"object_or_array"]
[self.view addSubview:label];
});
然后UI按预期立即更新。
有谁可以告诉我为什么会这样?
答案 0 :(得分:3)
正如@rmaddy所说:
线程注意事项
必须在主线程上对应用程序的用户界面进行操作。因此,您应该始终从应用程序主线程中运行的代码调用UIView类的方法。这可能不是绝对必要的唯一时间是创建视图对象本身,但所有其他操作应该在主线程上发生。
从这句话中,我推断出以下规则:
UIView
继承的类的实例应该只在主线程上调用方法(包括属性getter和setter)。-init*
)可以在任何线程中完成。以下是我感到满意的代码:
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(100, 200, 150, 150)]; // OK because -initWithFrame: is initialization
UIColor *color = [UIColor greenColor]; // OK because UIColor is not a subclass of UIView
NSString *text = jsonDict[@"object_or_array"];
dispatch_async(dispatch_get_main_queue(), ^{
label.backgroundColor = color;
label.text = text;
[self.view addSubview:label];
});
但实际上,最安全的是从主线程中完成所有操作:
dispatch_async(dispatch_get_main_queue(), ^{
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(100, 200, 150, 150)];
label.backgroundColor = [UIColor greenColor];
label.text = jsonDict[@"object_or_array"];
[self.view addSubview:label];
});
除非您遇到性能问题,否则没有理由不这样做。