使用" dispatch_async(dispatch_get_main_queue(),^ {block})更新UI

时间:2015-01-27 18:59:41

标签: ios cocoa-touch

我想在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按预期立即更新。

有谁可以告诉我为什么会这样?

1 个答案:

答案 0 :(得分:3)

正如@rmaddy所说:

  

线程注意事项

     

必须在主线程上对应用程序的用户界面进行操作。因此,您应该始终从应用程序主线程中运行的代码调用UIView类的方法。这可能不是绝对必要的唯一时间是创建视图对象本身,但所有其他操作应该在主线程上发生。

- UIView Class Reference

从这句话中,我推断出以下规则:

  • UIView继承的类的实例应该只在主线程上调用方法(包括属性getter和setter)。
  • UIKit对象的初始化方法(-init*)可以在任何线程中完成。
  • 任何方法都可以在UIKit类的实例上调用,而UIKit类不是从任何线程的UIView中分类的。

以下是我感到满意的代码:

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

除非您遇到性能问题,否则没有理由不这样做。