为什么一定要在主线程刷新UI?
安全+效率:因为UIKit框架不是线程安全的框架,当在多个线程进行UI操作,有可能出现资源抢夺,导致问题。

其实:在子线程是不能更新UI的, 看到能更新的结果只是个假象。因为:在子线程代码完成之后,回到主线程,然后执行了子线程的更新UI的代码,由于这个时间很短,所以看起来是能够在子线程刷新UI的。想验证的话也很简单,看下面demo:点击按钮,会开启一个子线程,然后在子线程中刷新该按钮的标题,再新建一个按钮,最后一行代码是延迟5秒。

- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.button];
} -(UIButton *)button{
if (!_button) {
_button = [[UIButton alloc] initWithFrame:CGRectMake(0, 100, SCREEN_WIDTH, 100)];
_button.backgroundColor = [UIColor yellowColor];
[_button addTarget:self action:@selector(btnClicked) forControlEvents:UIControlEventTouchUpInside];
[_button setTitle:@"UI" forState:UIControlStateNormal];
[_button setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
_button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
_button.titleLabel.font = [UIFont systemFontOfSize:13];
}
return _button;
} - (void)btnClicked {
[NSThread detachNewThreadSelector:@selector(uiRefreashTest) toTarget:self withObject:nil];
} - (void)uiRefreashTest {
NSLog(@"当前线程:%@", [NSThread currentThread]);
NSLog(@"主线程:%@", [NSThread mainThread]); //在子线程刷新该按钮的标题名字为子线程信息
NSString *subStr = [NSString stringWithFormat:@"子线程:%@", [NSThread currentThread]];
NSString *mainStr = [NSString stringWithFormat:@"主线程:%@", [NSThread mainThread]];
[_button setTitle:subStr forState:UIControlStateNormal];
CGRect labelTitleSize = [subStr boundingRectWithSize:CGSizeMake(SCREEN_WIDTH, SCREEN_HEIGHT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:13]} context:nil];
_button.frame = CGRectMake(0, 100, labelTitleSize.size.width+10, labelTitleSize.size.height+10); //在子线程新建一个按钮,标题名字为主线程信息
UIButton *newBtn = [[UIButton alloc] init];
newBtn.backgroundColor = [UIColor greenColor];
newBtn.titleLabel.font = [UIFont systemFontOfSize:13];
newBtn.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
[newBtn setTitle:mainStr forState:UIControlStateNormal];
[newBtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
CGRect labelTitleSize01 = [mainStr boundingRectWithSize:CGSizeMake(SCREEN_WIDTH, SCREEN_HEIGHT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:13]} context:nil]; newBtn.frame = CGRectMake(0, 250, labelTitleSize01.size.width+10, labelTitleSize01.size.height+10);
[self.view addSubview:newBtn]; //在这个子线程延迟5秒钟
sleep(5);
}

  

执行结果:

 
333.gif

结果分析:
从图中点击按钮后,虽然任务是在同一个子线程执行,但是并没有按顺序执行,而是首先立即执行NSLog日志输出,但是接下来并没有执行刷新按钮标题,和新建按钮的代码,而是优先执行sleep(5)延迟代码,然后才执行的刷新和新建控件的代码

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
转自简书
作者:wg刚
链接:https://www.jianshu.com/p/8d0aa880d55b
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

关于iOS刷新UI需要在主线程执行的更多相关文章

  1. WPF里面多线程访问UI线程、主线程的控件

    如果出现以下错误:调用线程无法访问此对象,因为另一个线程拥有该对象. 你就碰到多线程访问UI线程.主线程的控件的问题了. 先占位.

  2. iOS开发之GCD同步主线程、异步主线程

    /** 在主线程执行block */ + (void)gs_synExecuteOnMainThread:(void (^)(void))block { if ((nil == block) || ( ...

  3. iOS 安全地在主线程执行一个Block

    //主线程同步队列 #define dispatch_main_sync_safe(block)\ if ([NSThread isMainThread]) {\ block();\ } else { ...

  4. 在Qt中将函数发送到主线程执行

    考虑这样一种需求,使用Qt的线程类QThread在后台执行操作(比如说拷贝文件)的时候发生了错误,产生了一个错误信息需要提醒给用户,在后台输出很显然是不够的,因为用户可能根据就没有任何控制台可供程序输 ...

  5. 主线程中也不绝对安全的 UI 操作

    从最初开始学习 iOS 的时候,我们就被告知 UI 操作一定要放在主线程进行.这是因为 UIKit 的方法不是线程安全的,保证线程安全需要极大的开销.那么问题来了,在主线程中进行 UI 操作一定是安全 ...

  6. Android子线程更新UI主线程方法之Handler

    背景: 我们开发应用程序的时候,处于线程安全的原因子线程通常是不能直接更新主线程(UI线程)中的UI元素的,那么在Android开发中有几种方法解决这个问题,其中方法之一就是利用Handler处理的. ...

  7. 03_主线程联网问题&ANR&子线程不能修改UI

    如果不使用HAXM,恐怕网页源码查看器无法获取servlet的源码.初步猜测是安卓模拟器运行速度太慢了.如果CPU不支持VT-x的话,HAXM是安装不上的.所以可以先开启VT-x. 可以参考几篇文章h ...

  8. Android关于主线程和非主线程

    必须在主线程执行的任务: (1)UI更新 必须在非主线程中执行的任务 (1)Http请求 如执行:ImageHelper.getInstance().loadImageSync(picUrl); 外面 ...

  9. RxJava开发精要7 – Schedulers-解决Android主线程问题

    原文出自<RxJava Essentials> 原文作者 : Ivan Morgillo 译文出自 : 开发技术前线 www.devtf.cn 转载声明: 本译文已授权开发者头条享有独家转 ...

随机推荐

  1. 课上补做:用C语言编程实现ls命令

    课上补做:用C语言编程实现ls命令 一.有关ls ls :用来打印当前目录或者制定目录的清单,显示出文件的一些信息等. ls -l:列出长数据串,包括文件的属性和权限等数据 ls -R:连同子目录一同 ...

  2. centos7 系统优化脚本

    脚本一: #!/usr/bin/env bash #设置环境变量 export PATH=$PATH:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sb ...

  3. GPIO输入输出各种模式(推挽、开漏、准双向端口)详解

    转自:https://blog.csdn.net/techexchangeischeap/article/details/72569999 概述 能将处理器的GPIO(General Purpose ...

  4. 小程序navigateBack,子页面传值给父页面

    子页面 let page = getCurrentPages(); let prevPage = page[page.length - 2]; prevPage.setData({ lxr :item ...

  5. java工具类——java将一串数据按照gzip方式压缩和解压缩

    我要整理在工作中用到的工具类分享出来,也方便自己以后查阅使用,这些工具类都是我自己实际工作中使用的 import java.io.ByteArrayInputStream; import java.i ...

  6. 快速傅里叶变换(FFT)时间复杂度

    图:信号在时域上和频域上的直观表示 1. 计算一维离散傅里叶变换(DFT)公式如下: 其中,N表示数据长度.由上式可知,DFT的时间复杂度是O(N*N) 2. 一维FFT的时间复杂度为O(N*logN ...

  7. 容器化部署Cassandra高可用集群

    前提: 三台装有docker的虚拟机,这里用VM1,VM2,VM3表达(当然生产环境要用三个独立物理机,否则无高可用可言),装docker可参见Ubuntu离线安装docker. 开始部署: 部署图 ...

  8. docker swarm 部署服务时,限制服务启动后所在的机器

    借助容器技术,可以方便的在不同环境下部署服务,保证服务环境的一致性.docker swarm这个东西,可以方便的对容器进行编排管理. docker swarm集群中,有manager节点与worker ...

  9. SQLALchemy中关于复杂关系表模型的映射处理

    映射在第五步,我们还是一步一步来哈 一. 关系介绍 举一个比较经典的关系,部门与员工(以下是我的需求情况,算是把该有的关系都涉及到了) 1.每个部门会有很多成员(这里排除一个成员属于多个部门的情况) ...

  10. ssm注入失败

    今天做ssm整合时候,创建bean/注入一直出错,检查几遍没发现问题,后来发现犯了个低级错误,mapper.xml的<mapper namespace="XXXXX" > ...