网络操作不能直接写在主线程中 以及 为什么不能在子线程中更新UI控件的属性

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    //注意: 所有网络操作不能直接写在主线程中 因为所有的网络操作都是耗时的,如果加载到主线程中,会导致与用户的交互出现问题 ,所以要加载到子线程中
//    [self loadImage];

   [self performSelectorInBackground:@selector(loadImage) withObject:nil];

}

//加载网络图片
- (void)loadImage{
    //所有网络上的东西都是有地址的. 要获取网络数据,必须要知道这个网络数据的地址.
    NSURL *url = [NSURL URLWithString:@"http://b.hiphotos.baidu.com/image/pic/item/d788d43f8794a4c274c8110d0bf41bd5ad6e3928.jpg"];

    NSData *data = [NSData dataWithContentsOfURL:url];
    self.imageData = data;
    NSLog(@"%@",[NSThread currentThread]);
    //在子线程中直接更新UI会报错, 千万不能在子线程中更新UI (假如允许任意子线程访问、修改UI控件的属性,这就需要对多个新线程的并发访问进行同步控制,否则多个线程将会破坏UI控件内部状态的完整性)
//    self.imageView.image = [UIImage imageWithData:data];

//    解决方法(网络操作必须在子线程中,网络操作完成后,而更新UI操作又不能在子线程中,这里用到线程间的通信)
    //waitUntilDone : 这个参数表示是否等方法执行完成之后, 才去执行后面的代码, 一般我们写NO
    [self performSelectorOnMainThread:@selector(updateImageView) withObject:nil waitUntilDone:NO];

}

- (void)updateImageView{
    self.imageView.image = [UIImage imageWithData:self.imageData];

}

1.所有网络操作不能直接写在主线程中 因为所有的网络操作都是耗时的,如果加载到主线程中,会导致与用户的交互出现问题 ,所以要加载到子线程中

2.在子线程中直接更新UI会报错, 千万不能在子线程中更新UI (假如允许任意子线程访问、修改UI控件的属性,这就需要对多个新线程的并发访问进行同步控制,否则多个线程将会破坏UI控件内部状态的完整性)

3.解决方法(网络操作必须在子线程中,网络操作完成后,而更新UI操作又不能在子线程中,这里用到线程间的通信)

//waitUntilDone : 这个参数表示是否等方法执行完成之后, 才去执行后面的代码, 一般我们写NO

时间: 2024-08-03 07:06:35

网络操作不能直接写在主线程中 以及 为什么不能在子线程中更新UI控件的属性的相关文章

QT多线程的简单使用,主线程发一份数据,子线程收两份数据

先看效果图,示例发送数据“Hello World” 主线程:0x16f54aeda20,另两个子线程分别是0x4f1baff690.0x4f1baff6a0 因为在子线程中加了200ms.400ms延迟,所以打印是有先后顺序的 核心代码也就一丢丢.代码逻辑就是使用信号与槽使用线程之间产生联系 1 MfBusiness::MfBusiness(QObject *parent) : QObject(parent) 2 { 3 connect(&se,&MfSendData::Sgl_Send,

在子线程中创建Handler和looper并与主线程进行交互

分析完上面那篇文章,基本理解了handler的实现原理,乘热打铁,这里我们利用handler原理,在子线程中创建一个handler和looper 可能很多面试时候问道,子线程中能不能new一个handler ? 答案是可以的,但是因为主线程系统默认在ActivityThread中已将帮我们创建好一个looper和MessagQueue,我们不需要手动去创建 (手动创建会出错,因为一个线程中默认只运行一个looper和MessageQueue,具体见ThreadLocal代码原理), 而子线程中没

Android新线程中更新主线程中的UI控件

Android中的View都不是线程安全的,所以如果在某一个新线程中直接更新主线程中的UI控件时就会报如下错误: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. 为了解决在另一个线程中更新UI控件的问题,我们可以使用如下几种解决方案: 1. 自己写Handler解决,参见<And

winform进程间操作UI控件

一,问题说明. 当在主线程之外新建一个线程之后,我们想通过新建线程修改主界面控件的属性等操作,此时,Windows会报错,提示进程间操作UI无效. 二,解决方法. 1,并不高明的做法,有一定作用,并不推荐. public Form1() { InitializeComponent(); CheckForIllegalCrossThreadCalls = false;//这种设置相当于让vs同意这样进程间操作 } 2,利用委托来进行操作.相当于在新建进程和主进程间出现了一个第三方,这个第三方把新建

Delphi7从子线程中发送消息到主线程触发事件执行

[转载]Delphi7从子线程中发送消息到主线程触发事件执行 在对数据库的操作时,有时要用一个子线程来进行后台的数据操作.比如说数据备份,转档什么的.在主窗口还能同是进行其它操作.而有时后台每处理一个数据文件,要向主窗口发送消息,让主窗口实时显示处理进度在窗口上(可视),同时进行日志处理等.我用的是下面的方法: [1]用到的API函数: RegisterWindowsMessage ---------------------- 函数功能:该函数定义一个新的窗口消息,该消息确保在系统中是唯一的.返

在子线程中更改主线程中的控件的信息,在子线程中用toast

一丶在子线程中不允许更改主线程中的控件的信息,也不允许在子线程中用toast,我们要更改的话 (1)消息机制:使用handler (由主线程调用) 在主程序中Handler handler = new Handler(){ public void handleMessage(Message msg){ int type = msg.what ;//拿到msg的类型,再判断            switch (type) {                case SUCCESS:      

【iOS开发每日小笔记(九)】在子线程中使用runloop,正确操作NSTimer计时的注意点 三种可选方法

这篇文章是我的[iOS开发每日小笔记]系列中的一片,记录的是今天在开发工作中遇到的,可以用很短的文章或很小的demo演示解释出来的小心得小技巧.它们可能会给用户体验.代码效率得到一些提升,或是之前自己没有接触过的技术,很开心的学到了,放在这里得瑟一下.其实,90%的作用是帮助自己回顾.记忆.复习. 一直想写一篇关于runloop学习有所得的文章,总是没有很好的例子.正巧自己的上线App Store的小游戏<跑酷好基友>(https://itunes.apple.com/us/app/pao-k

在子线程中使用runloop,正确操作NSTimer计时的注意点 三种可选方法

游戏中有一个计时功能.在1.0版本中,使用了简单的在主线程中调用: 1 + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo; 的方法.但是当每0.01秒进行一次repeat操作时,NSTimer是不准的,严重滞后,而改成0.1秒repeat操作,则这种

多线程操作UI控件——DataGridView假死现象

在多线程编程中,如果你从非创建这个控件的线程中访问这个控件或者操作这个控件的话就会抛出这个异常.这是微软为了保证线程安全以及提高代码的效率所做的改进,但是也 给大家带来很多不便. 今天我就遇到了一个类似的问题,对DataGridView指定 DataSource 来填充数据,更新数据的时候,会导致DataGridView出现假死,显示错误或者滚动条无法显示的问题,在保证了DataGridView的ScrollBars设置为了Both,数据量大于DataGridView显示的的范围,而且没有冻结列