ios - 使用“dispatch_async(dispatch_get_main_queue(),^{block})”更新UI

标签 ios cocoa-touch

我想更新 NSURLSession 的完成 block 中的 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 按预期立即更新。

谁能告诉我这是为什么?

最佳答案

@rmaddy曾说过:

Threading Considerations

Manipulations to your application’s user interface must occur on the main thread. Thus, you should always call the methods of the UIView class from code running in the main thread of your application. The only time this may not be strictly necessary is when creating the view object itself but all other manipulations should occur on the main thread.

UIView Class Reference

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

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

这是我觉得舒服的代码:

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

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

关于ios - 使用“dispatch_async(dispatch_get_main_queue(),^{block})”更新UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28177978/

相关文章:

objective-c - UITableView 没有取消选择?

ios - 我可以在 UITextField 上设置插入点吗

iphone - CIFeature : Is there only Face Detection? 我可以添加行为吗?

ios - 如何将图像从一个 View 传递到另一个 View

ios - 接收用户交互的滚轮动画

ios - 是否有可能知道我的应用程序是否是第一次在 xcode 中运行?

javascript - UIWebView 使用 elementFromPoint() 获取图片 url

ios - 从底部向上布局 SwiftUI 列表单元格

ios - Swift 如何在 AnyObject 数组中查找对象

ios - 如何将 URL 读入 AVURLAsset