本文首发在我的个人博客: blog.shenyuanluo.com,喜欢的朋友欢迎订阅。

考虑以下代码,最终会输出什么?

  1. 例子①:

    - (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 方法。
  2. 例子②:
    - (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 作如下解释:
  3. 例子③:
    - (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 (对比 例子⑥例子)。
  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 解释如下:
  5. 例子⑤:
    - (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 解释如下:
  6. 例子⑥:
    - (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
  7. 例子⑦:
    - (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
  8. 例子⑧:
    - (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

小结:

  1. 常用 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;
    复制代码
  2. 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 就会退出。
  3. 更多关于 NSRunLoop的退出方式 可以看这篇博文

参考

  1. NSRunLoop的退出方式

转载于:https://juejin.im/post/5c637a1ff265da2dbc596ec2

关于 performSelector 的一些小探讨相关推荐

  1. 关于新年发红包的小探讨

    关于新年发红包的探讨 涉及红包的对象归为两类,发方和收方,收方指的是过年收红包的孩子,发方指的是父母和其他可能会发红包的亲戚们. 作为孩子这一方,要想尽可能争取更多红包,可以从两方面来努力:一是积极表 ...

  2. 【system verilog】非合并数组、合并数组、混合数组和多维数组的小探讨

    前言 来了的话点个赞吱一声在走呀~~~ 因为需要解决一个问题,所以决定对合并数组/非合并数组以及混合场景进行进行一下探索. 问题 已知一个多维混合数组的定义为: bit [3:0][7:0][15:0 ...

  3. 数据库中存储图片等文件的小探讨

    关于在数据库中存储图片文件的问题 直接存储在数据库中 这样做有什么问题 另寻方法 或许接下来的文章没有明显的帮到你解决存储问题,但花点时间耐心的往下读一读,在思路上或许对你可以有点帮助! 直接存储在数 ...

  4. 软件测试颗粒度,测试用例粒度粗细的划分

    在设计测试用例工作中,把握测试用例粒度的粗细是件很伤神的事:测试用例写得很细,会带来很多问题:首先是效率问题,测试人员的首要任务有效地测试产品尽可能多的发现产品缺陷,如果测试用例写的过细,在设计测试用 ...

  5. 电力电子转战数字IC——我的IC笔试(2022.10.14更新)

    IC笔试有:JL科技.TR半导体.HZW.MX半导体.RSKX.TCL 部分题目暂时还是做不出来,先好好复习一遍,会有柳暗花明的时候的. 目录 RY10.11 TCL10.9 位宽定义正确的是 逻辑与 ...

  6. 审视自己也是一种进步

    有时候真的很有必要审视一下自己.这两天我也和我一个发小探讨到这个问题,关于自己的短板和优点,有些短板不是自己不明白,内心比谁都明白,但就是难以改变.有种基因式的存在,但内心还是有一万个需要改变的念想. ...

  7. 智商捉急人士求金融数学与matlab相关指导

    想学习一下,金融相关数学,运用matlab和python进行一些小探讨,数学考上研究生后基本放下.求211以上高校在校统计.应用数学.金融数学.量化金融相关专业的大神辅导一下,感恩!薪资微薄,望不要嫌 ...

  8. 最终幻想:探讨小鹏G9 800V 高压动力系统和架构路线

    大家好,我是LEON. 今天和大家分享的是小鹏G9的高压系统. 更多内容请关注:点击关注 1 G9配置介绍 在分享之前,先和大家快速介绍下G9的价格配置:售价区间为 30.99-46.99 万.续航覆 ...

  9. 小程序高级电商前端第2周深入理解REST API开发规范 开启三端分离编程之旅<二>----scroll-view组件的灵活应用、async和await问题探讨、spu-scroll自定义组件

    前言: 转眼距离上一次写博文又过去一个月了,今年的博文节奏已经彻底被打破了: 真的是有心无力了,其原因在之前也提到过,组织架构调整,各种考核(跨领域性质的考核)实行末尾淘汰制,说不出的酸楚,不过换个心 ...

最新文章

  1. 星际2正在等待暴雪服务器的响应,win7系统玩星际2一直停留在"正在更新暴雪启动器"页面的解决方法...
  2. CrowdStrike加入VirusTotal阵营
  3. zabbix server和client的快速部署
  4. WEB测试总结 (架构,设计)精华部分(转)
  5. Python——高阶函数
  6. USACO 5.3 Window Area
  7. 对中文版“Siri”打个招呼吧!
  8. python 城市地图_使用底图获取城市地图的最佳方法? - python
  9. Opencv2与Opencv4共存
  10. win7电脑便签怎么弄
  11. VS2017使用C#编写COM组件
  12. oracle 索引原理
  13. python3数据科学入门与实战技巧_Python3数据科学入门与实战
  14. 关于企业工业控制系统的网络安全保护设计方案
  15. 微信小程序应用开发赛作品综合开发记录——晋鹿文旅(云开发——概览)
  16. 一个小需求引发的思考
  17. Linux环境下,文件的压缩/解压
  18. 关闭VScode界面输入右上角的累加数字
  19. excel vlookup函数使用
  20. BRVAH的BaseRecyclerViewAdapterHelper与MVVM模式优雅结合,Recyclerview如何在Databinding中快捷、方便地使用(三)

热门文章

  1. Android-Spinner下拉列表Demo
  2. centos静态IP配置方法
  3. WinForm下ComboBox获取绑定对象集的SelectedValue补充
  4. Swift的类,及存储属性,计算发发样码
  5. 深入redis内部--内存管理
  6. css样式IE8强制兼容IE7
  7. GentleNet使用之详细图解[语法使用增强版]
  8. jquery的文档处理(部分)
  9. 修改Exchange邮件报警信息
  10. 宽带服务价值链之:ISP,ICP,ASP,IDC,CDN