关于 performSelector 的一些小探讨
本文首发在我的个人博客: blog.shenyuanluo.com,喜欢的朋友欢迎订阅。
考虑以下代码,最终会输出什么?
- 例子①:
- (void)viewDidLoad {[super viewDidLoad];NSLog(@"1 - %@", [NSThread currentThread]);dispatch_async(dispatch_get_global_queue(0, 0), ^{NSLog(@"2 - %@", [NSThread currentThread]);[self performSelector:@selector(test)withObject:nil];NSLog(@"4 - %@", [NSThread currentThread]);}); }- (void)test {NSLog(@"3 - %@", [NSThread currentThread]); } 复制代码
- 输出结果:
1,2,3,4
- 原因: 因为
performSelector:withObject:
会在当前线程立即执行指定的 selector 方法。
- 输出结果:
- 例子②:
- (void)viewDidLoad {[super viewDidLoad];NSLog(@"1 - %@", [NSThread currentThread]);dispatch_async(dispatch_get_global_queue(0, 0), ^{NSLog(@"2 - %@", [NSThread currentThread]);[self performSelector:@selector(test)withObject:nilafterDelay:0];NSLog(@"4 - %@", [NSThread currentThread]);}); }- (void)test {NSLog(@"3 - %@", [NSThread currentThread]); } 复制代码
- 输出结果:
1,2,4
- 原因: 因为
performSelector:withObject:afterDelay:
实际是往 RunLoop 里面注册一个定时器,而在子线程中,RunLoop 是没有开启(默认)的,所有不会输出3
。官网 API 作如下解释:
- 输出结果:
- 例子③:
- (void)viewDidLoad {[super viewDidLoad];NSLog(@"1 - %@", [NSThread currentThread]);dispatch_async(dispatch_get_global_queue(0, 0), ^{NSLog(@"2 - %@", [NSThread currentThread]);[self performSelector:@selector(test)withObject:nilafterDelay:0];[[NSRunLoop currentRunLoop] run];NSLog(@"4 - %@", [NSThread currentThread]);}); }- (void)test {NSLog(@"3 - %@", [NSThread currentThread]); } 复制代码
- 输出结果:
1,2,3,4
- 原因: 由于
[[NSRunLoop currentRunLoop] run];
会创建的当前子线程对应的 RunLoop 对象并启动了,因此可以执行test
方法;并且test
执行完后,RunLoop 中注册的定时器已经无效,所以还可以输出4
(对比 例子⑥例子)。
- 输出结果:
- 例子④:
- (void)viewDidLoad {[super viewDidLoad];NSLog(@"1 - %@", [NSThread currentThread]);dispatch_async(dispatch_get_global_queue(0, 0), ^{NSLog(@"2 - %@", [NSThread currentThread]);[self performSelector:@selector(test)onThread:[NSThread currentThread]withObject:nilwaitUntilDone:YES];NSLog(@"4 - %@", [NSThread currentThread]);}); }- (void)test {NSLog(@"3 - %@", [NSThread currentThread]); } 复制代码
- 输出结果:
1,2,3,4
- 原因: 因为
performSelector:onThread:withObject:waitUntilDone:
会在指定的线程执行,而执行的策略根据参数wait
处理,这里传YES
表明将会立即阻断 指定的线程 并执行指定的selector
。官网 API 解释如下:
- 输出结果:
- 例子⑤:
- (void)viewDidLoad {[super viewDidLoad];NSLog(@"1 - %@", [NSThread currentThread]);dispatch_async(dispatch_get_global_queue(0, 0), ^{NSLog(@"2 - %@", [NSThread currentThread]);[self performSelector:@selector(test)onThread:[NSThread currentThread]withObject:nilwaitUntilDone:NO];NSLog(@"4 - %@", [NSThread currentThread]);}); }- (void)test {NSLog(@"3 - %@", [NSThread currentThread]); } 复制代码
- 输出结果:
1,2,4
- 原因: 因为
performSelector:onThread:withObject:waitUntilDone:
会在指定的线程执行,而执行的策略根据参数wait
处理,这里传NO
表明不会立即阻断 指定的线程 而是将selector
添加到指定线程的 RunLoop 中等待时机执行。(该例子中,子线程 RunLoop 没有启动,所有没有输出3
)官网 API 解释如下:
- 输出结果:
- 例子⑥:
- (void)viewDidLoad {[super viewDidLoad];NSLog(@"1 - %@", [NSThread currentThread]);dispatch_async(dispatch_get_global_queue(0, 0), ^{NSLog(@"2 - %@", [NSThread currentThread]);[self performSelector:@selector(test)onThread:[NSThread currentThread]withObject:nilwaitUntilDone:NO];[[NSRunLoop currentRunLoop] run];NSLog(@"4 - %@", [NSThread currentThread]);}); }- (void)test {NSLog(@"3 - %@", [NSThread currentThread]); } 复制代码
- 输出结果:
1,2,3
- 原因: 由于
[[NSRunLoop currentRunLoop] run];
已经创建的当前子线程对应的 RunLoop 对象并启动了,因此可以执行test
方法;但是test
方法执行完后,RunLoop 并没有结束(使用这种启动方式,RunLoop 会一直运行下去,在此期间会处理来自输入源的数据,并且会在NSDefaultRunLoopMode
模式下重复调用runMode:beforeDate:
方法)所以无法继续输出4
。
- 输出结果:
- 例子⑦:
- (void)viewDidLoad {[super viewDidLoad];NSLog(@"1 - %@", [NSThread currentThread]);dispatch_async(dispatch_get_global_queue(0, 0), ^{NSLog(@"2 - %@", [NSThread currentThread]);[self performSelector:@selector(test)onThread:[NSThread currentThread]withObject:nilwaitUntilDone:NO];[[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];NSLog(@"4 - %@", [NSThread currentThread]);}); }- (void)test {NSLog(@"3 - %@", [NSThread currentThread]); } 复制代码
- 输出结果:
1,2,3
- 原因: 由于
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];
已经创建的当前子线程对应的 RunLoop 对象并启动了,因此可以执行test
方法;但是test
方法执行完后,RunLoop 并没有结束(使用这种启动方式,可以设置超时时间,在超时时间到达之前,runloop会一直运行,在此期间runloop会处理来自输入源的数据,并且会在NSDefaultRunLoopMode
模式下重复调用runMode:beforeDate:
方法)所以无法继续输出4
。
- 输出结果:
- 例子⑧:
- (void)viewDidLoad {[super viewDidLoad];NSLog(@"1 - %@", [NSThread currentThread]);dispatch_async(dispatch_get_global_queue(0, 0), ^{NSLog(@"2 - %@", [NSThread currentThread]);[self performSelector:@selector(test)onThread:[NSThread currentThread]withObject:nilwaitUntilDone:NO];[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopModebeforeDate:[NSDate distantFuture]];NSLog(@"4 - %@", [NSThread currentThread]);}); }- (void)test {NSLog(@"3 - %@", [NSThread currentThread]); } 复制代码
- 输出结果:
1,2,3,4
- 原因: 由于
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
已经创建的当前子线程对应的 RunLoop 对象并启动了,因此可以执行test
方法;而且test
方法执行完后,RunLoop 立刻结束(使用这种启动方式 ,RunLoop 会运行一次,超时时间到达或者第一个input source
被处理,则 RunLoop 就会退出)所以可以继续输出4
。
- 输出结果:
小结:
- 常用 performSelector 方法
- 常用的 perform,是 NSObject.h 头文件下的方法:
- (id)performSelector:(SEL)aSelector; - (id)performSelector:(SEL)aSelector withObject:(id)object; - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2; 复制代码
- 可以 delay 的 perform,是 NSRunLoop.h 头文件下的方法:
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray<NSRunLoopMode> *)modes; - (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay; 复制代码
- 可以 指定线程 的 perform,是 NSThread 头文件下的方法:
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array; - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait; - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array; - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait; - (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg; 复制代码
- RunLoop 退出方式:
- 使用
- (void)run;
启动,RunLoop 会一直运行下去,在此期间会处理来自输入源的数据,并且会在NSDefaultRunLoopMode
模式下重复调用runMode:beforeDate:
方法; - 使用
- (void)runUntilDate:(NSDate *)limitDate;
启动,可以设置超时时间,在超时时间到达之前,RunLoop 会一直运行,在此期间 RunLoop 会处理来自输入源的数据,并且也会在NSDefaultRunLoopMode
模式下重复调用runMode:beforeDate:
方法; - 使用
- (void)runMode:(NSString *)mode beforeDate:(NSDate *)limitDate;
启动,RunLoop 会运行一次,超时时间到达或者第一个input source
被处理,则 RunLoop 就会退出。
- 使用
- 更多关于 NSRunLoop的退出方式 可以看这篇博文
参考
- NSRunLoop的退出方式
转载于:https://juejin.im/post/5c637a1ff265da2dbc596ec2
关于 performSelector 的一些小探讨相关推荐
- 关于新年发红包的小探讨
关于新年发红包的探讨 涉及红包的对象归为两类,发方和收方,收方指的是过年收红包的孩子,发方指的是父母和其他可能会发红包的亲戚们. 作为孩子这一方,要想尽可能争取更多红包,可以从两方面来努力:一是积极表 ...
- 【system verilog】非合并数组、合并数组、混合数组和多维数组的小探讨
前言 来了的话点个赞吱一声在走呀~~~ 因为需要解决一个问题,所以决定对合并数组/非合并数组以及混合场景进行进行一下探索. 问题 已知一个多维混合数组的定义为: bit [3:0][7:0][15:0 ...
- 数据库中存储图片等文件的小探讨
关于在数据库中存储图片文件的问题 直接存储在数据库中 这样做有什么问题 另寻方法 或许接下来的文章没有明显的帮到你解决存储问题,但花点时间耐心的往下读一读,在思路上或许对你可以有点帮助! 直接存储在数 ...
- 软件测试颗粒度,测试用例粒度粗细的划分
在设计测试用例工作中,把握测试用例粒度的粗细是件很伤神的事:测试用例写得很细,会带来很多问题:首先是效率问题,测试人员的首要任务有效地测试产品尽可能多的发现产品缺陷,如果测试用例写的过细,在设计测试用 ...
- 电力电子转战数字IC——我的IC笔试(2022.10.14更新)
IC笔试有:JL科技.TR半导体.HZW.MX半导体.RSKX.TCL 部分题目暂时还是做不出来,先好好复习一遍,会有柳暗花明的时候的. 目录 RY10.11 TCL10.9 位宽定义正确的是 逻辑与 ...
- 审视自己也是一种进步
有时候真的很有必要审视一下自己.这两天我也和我一个发小探讨到这个问题,关于自己的短板和优点,有些短板不是自己不明白,内心比谁都明白,但就是难以改变.有种基因式的存在,但内心还是有一万个需要改变的念想. ...
- 智商捉急人士求金融数学与matlab相关指导
想学习一下,金融相关数学,运用matlab和python进行一些小探讨,数学考上研究生后基本放下.求211以上高校在校统计.应用数学.金融数学.量化金融相关专业的大神辅导一下,感恩!薪资微薄,望不要嫌 ...
- 最终幻想:探讨小鹏G9 800V 高压动力系统和架构路线
大家好,我是LEON. 今天和大家分享的是小鹏G9的高压系统. 更多内容请关注:点击关注 1 G9配置介绍 在分享之前,先和大家快速介绍下G9的价格配置:售价区间为 30.99-46.99 万.续航覆 ...
- 小程序高级电商前端第2周深入理解REST API开发规范 开启三端分离编程之旅<二>----scroll-view组件的灵活应用、async和await问题探讨、spu-scroll自定义组件
前言: 转眼距离上一次写博文又过去一个月了,今年的博文节奏已经彻底被打破了: 真的是有心无力了,其原因在之前也提到过,组织架构调整,各种考核(跨领域性质的考核)实行末尾淘汰制,说不出的酸楚,不过换个心 ...
最新文章
- 星际2正在等待暴雪服务器的响应,win7系统玩星际2一直停留在"正在更新暴雪启动器"页面的解决方法...
- CrowdStrike加入VirusTotal阵营
- zabbix server和client的快速部署
- WEB测试总结 (架构,设计)精华部分(转)
- Python——高阶函数
- USACO 5.3 Window Area
- 对中文版“Siri”打个招呼吧!
- python 城市地图_使用底图获取城市地图的最佳方法? - python
- Opencv2与Opencv4共存
- win7电脑便签怎么弄
- VS2017使用C#编写COM组件
- oracle 索引原理
- python3数据科学入门与实战技巧_Python3数据科学入门与实战
- 关于企业工业控制系统的网络安全保护设计方案
- 微信小程序应用开发赛作品综合开发记录——晋鹿文旅(云开发——概览)
- 一个小需求引发的思考
- Linux环境下,文件的压缩/解压
- 关闭VScode界面输入右上角的累加数字
- excel vlookup函数使用
- BRVAH的BaseRecyclerViewAdapterHelper与MVVM模式优雅结合,Recyclerview如何在Databinding中快捷、方便地使用(三)