使用“dispatch_async(dispatch_get_main_queue(),^ {block})更新UI [英] Updating the UI using "dispatch_async(dispatch_get_main_queue(),^{block})

查看:133
本文介绍了使用“dispatch_async(dispatch_get_main_queue(),^ {block})更新UI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想更新NSURLSession的完成块中的UI。
初始实现没有立即更新UI。它更新UI可能20秒后。这里是初始实现。

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

[任务恢复];

我移动了 label.text = jsonDict [@] object_or_array的位置] 在主队列中,如下所示。

  dispatch_async(dispatch_get_main_queue(),^ {
label.text = jsonDict [@object_or_array]
[self.view addSubview:label];
});

然后UI会按预期立即更新。



任何人都可以告诉我为什么会这样?

解决方案

a href =http://stackoverflow.com/questions/28177978/updating-the-ui-using-dispatch-asyncdispatch-get-main-queue-block#comment44725392_28177978> @rmaddy 说: p>


线程注意事项



对应用程序用户界面的操作必须在主线程上进行。因此,应该始终从应用程序的主线程中运行的代码调用UIView类的方法。只有在创建视图对象本身时,所有其他操作都应该在主线程上进行。


- UIView类参考



从这个引用推导出以下规则:




  • 继承自

  • 初始化方法( -init * / $>
  • 任何方法都可以从任何线程的UIView子类中调用UIKit类的实例。
  • li>


这里是我感觉舒服的代码:

 code> UILabel * label = [[UILabel alloc] initWithFrame:CGRectMake(100,200,150,150)]; // OK因为-initWithFrame:是初始化
UIColor * color = [UIColor greenColor]; // OK因为UIColor不是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];
} );

除非遇到性能问题,否则没有理由。


I wanted to update the UI in the NSURLSession's completion block. The initial implementation didn't update the UI immediately. It updated the UI maybe 20 seconds later. Here is the initial implementation.

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

I moved the location of the label.text = jsonDict[@"object_or_array"] inside the main queue as following.

 dispatch_async(dispatch_get_main_queue(), ^{ 
                label.text = jsonDict[@"object_or_array"]
                [self.view addSubview:label];
            });

Then the UI was updated immediately as expected.

Could anyone tell me why this is?

解决方案

As @rmaddy has said:

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

From this quote, I infer the following rules:

  • Instances of classes that inherit from UIView should only have methods called on the main thread (including property getters and setters).
  • Initialization methods (-init*) of UIKit objects can be done in any thread.
  • Any method can be called on instances of UIKit classes not sub-classed from UIView from any thread.

Here is the code I would feel comfortable with:

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

But really, the safest is to do it all from the main thread:

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

Unless you are running into performance issues, there is no reason not to.

这篇关于使用“dispatch_async(dispatch_get_main_queue(),^ {block})更新UI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆