参考:http://blog.csdn.net/agonie201218/article/details/51115677

https://www.jianshu.com/p/edbe946c8a11

https://segmentfault.com/a/1190000011151505

什么是RunLoop

从字面意思看,就是运行循环,兜圈圈儿。

  • 运行循环
  • 一个线程对应一个RunLoop,主线程的RunLoop默认已经启动,子线程的RunLoop得手动启动(调用run方法)
  • RunLoop只能选择一个Mode启动,如果当前Mode中没有任何Source(Sources0、Sources1)、Timer,那么就直接退出RunLoop。 

基本作用

1、保持程序的持续运行,接受用户输入。 
2、处理APP中的各种事件(如触摸事件、定时器事件、Selector事件) 
3、节省CPU资源,提高程序性能:该做事时做事,该休息时休息。 
4、调用解耦。

RunLoop内部实现

其实它内部就是do-while循环,在这个循环内部不断地处理各种任务(比如Source、Timer、Observer)。

void message(int num) {printf("执行第%i个任务", num);
}int main(int argc, const char * argv[]) {do {printf("有事吗? 没事我睡了");int number;scanf("%i", &number);message(number);} while (1);return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

iOS 中有2套API来访问和使用RunLoop

  • Foundation –> NSRunLoop
  • Core Foundation – >CFRunLoopRef

NSRunLoop 和 CFRunLoopRef都代表着RunLoop对象 
NSRunLoop是基于CFRunLoopRef的一层OC包装,所以要了解RunLoop内部结构,需要研究CFRunLoopRef层面的API(Core Foundation层面)。

获得RunLoop对象

Foundation

[NSRunLoop currentRunLoop]; // 获得当前线程的RunLoop对象
[NSRunLoop mainRunLoop]; // 获得主线程的RunLoop对象
  • 1
  • 2

Core Foundation

CFRunLoopGetCurrent(); // 获得当前线程的RunLoop对象
CFRunLoopGetMain(); // 获得主线程的RunLoop对象
  • 1
  • 2

RunLoop与线程

每条线程都有唯一的一个与之对应的RunLoop对象。 主线程的RunLoop已经创建好了,子线程的RunLoop需要主动创建。 
RunLoop在第一次获取时创建,在线程结束时销毁。

RunLoop的结构

Core Foundation 中关于RunLoop的5个类

CFRunLoopRef  
CFRunLoopModeRef 
CFRunLoopTimerRef 
CFRunLoopObserveRef 
CFRunLoopSource

  • CFRunLoopModeRef代表RunLoop的运行模式,系统默认注册了5个Mode

    • NSDefaultRunLoopMode:App的默认Mode,通常主线程是在这个Mode下运行,RunLoop在同一时段只能且必须在一种特定Mode下Run,更换Mode时, 需要暂停当前的Loop,然后重启新的Loop。

      • NSDefalutRunLoopMode      默认状态.空闲状态
      • UITrackingRunLoopMode     滑动ScrollView
      • UIInitializationRunLoopMode    私有,App启动时
      • NSRunLoopCommonModes     默认包括上面第一和第二
    • UITrackingRunLoopMode:界面跟踪Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响
    • NSRunLoopCommonModes: 这是一个占位用的Mode,不是一种真正的Mode。
  • CFRunLoopTimerRef是基于时间的触发器 
    • CFRunLoopTimerRef基本上说的就是NSTimer,它受RunLoop的Mode影响。
  • CFRunLoopSourceRef是事件源(输入源) 
    • Source0:处理App内部事件,App自己负责管理(触发),如UIEvent,CFSocket。
    • Source1:由RunLoop和内核管理,Mach port驱动,如CFMachPort、CFMessagePort。
  • CFRunLoopObserverRef是观察者,能够监听RunLoop的状态改变,向内部报告RunLoop当前状态的更改,框架中很多机制都由RunLoopObserve触发,如 CAAnimation。

打印activity,查看RunLoop运行状态

// 1.创建Observer
// 第一个参数:用于分配该observer对象的内存
// 第二个参数:用以设置该observer所要关注的的事件
// 第三个参数:用于标识该observer是在第一次进入run loop时执行, 还是每次进入run loop处理时均执行
// 第四个参数:用于设置该observer的优先级
// 第五个参数: observer监听到事件时的回调blockCFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {switch(activity){case kCFRunLoopEntry:NSLog(@"即将进入loop");break;case kCFRunLoopBeforeTimers:NSLog(@"即将处理timers");break;case kCFRunLoopBeforeSources:NSLog(@"即将处理sources");break;case kCFRunLoopBeforeWaiting:NSLog(@"即将进入休眠");break;case kCFRunLoopAfterWaiting:NSLog(@"刚从休眠中唤醒");break;case kCFRunLoopExit:NSLog(@"即将退出loop");break;default:break;}});//     2.添加监听/*第一个参数: 给哪个RunLoop添加监听第二个参数: 需要添加的Observer对象第三个参数: 在哪种模式下监听*/CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopDefaultMode);//     3,释放observerCFRelease(observer);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

RunLoop事件队列

每次运行run loop,你线程的run loop对会自动处理之前未处理的消息,并通知相关的观察者。具体的顺序如下:



RunLoopRunLoop的应用

NSTimer

设置RunLoopMode,让NSTimer不影响其他刷新,默认情况下NSTimer被加入NSDefalutRunLoopMode

如果不想让NSTimer受到组件或者动画影响,就添加到NSRunLoopCommonModes:

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(ddd) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
  • 1
  • 2

常驻线程

AFNetWorking 中创建RunLoop,创建一个常驻服务线程的很好的方法

  • 必须调用run才会执行死循环
  • NSRunLoop的model中必须有source/timer,死循环才不会退出
[[NSThread currentThread] setName:@"AFNetworking"];
NSRunLoop *runloop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefalutRunLoopMode]//一直活着[runLoop run];
  • 1
  • 2
  • 3
  • 4
  • 5

自动释放池

activities = 0x1 = 1
1: 即将进入RunLoop : 创建一个自动释放池
activities = 0xa0 = 160 = 128 + 32
32:即将休眠 : 释放上一次的自动释放池, 创建一个新的自动释放池
128:即将退出RunLoop : 释放自动释放池
  • 1
  • 2
  • 3
  • 4
  • 5

让Crash的APP回光返照,接到Crash的Signal后手动重启RunLoop

CFRunLoopRef runloop = CFRunLoopGetCurrent();
NSArray *allModes = CFBridgingRelease(CFRunLoopCopyAllModes(runLoop));
while(1){
for (NSString *mode in allModes){CFRunLoopInMode((CFStringRef)mode,0.001,false);
}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

一个TableView延迟加载图片的新思路

[self.avatarImageView performSelector:@selector(serImage:) withObjetc:downloadedImage afterDelay:0 inModes:@[NSDefaultRunLoopMode]];+ (NSThread *)networkRequestThread {static NSThread *networkRequestThread = nil;static dispatch_once_t oncePredicate;dispatch_once(&oncePredicate, ^{networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];[networkRequestThread start];});return networkRequestThread;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

iOS高级面试之NSRunLoop须知相关推荐

  1. iOS高级面试之NSNotificationCenter是同步操作还是异步操作

    转载:http://blog.csdn.net/u014220518/article/details/70598063 :http://blog.csdn.net/intheair100/articl ...

  2. 最新2022【iOS开发面试真题】初级,中级,高级

    前言: 我是一名开发者,一个iOS交流圈子的维护者,对于程序员来说,要学习的知识内容.技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们! 标语:不要浪费 ...

  3. 【iOS高级资深工程师面试篇】⑪、2022年,金九银十我为你准备了《iOS高级资深工程师面试知识总结》 算法部分 字符串反转-链表反转-有序数组组合-Hash算法-查找两个子视图的共同父视图

    iOS高级资深工程师面试篇系列 - 已更新3篇 UI部分1/3 -UITableView-事件传递&视图响应 UI部分2/3 -图像显示原理-UI卡顿&掉帧 UI部分3/3 -UIVi ...

  4. 【iOS高级资深工程师面试篇】①、2022年,金九银十我为你准备了《iOS高级资深工程师面试知识总结》 UI部分2/3 -图像显示原理-UI卡顿掉帧

    iOS高级资深工程师面试篇系列 - 已更新3篇 UI部分1/3 -UITableView-事件传递&视图响应 UI部分2/3 -图像显示原理-UI卡顿&掉帧 UI部分3/3 -UIVi ...

  5. 【iOS高级资深工程师面试篇】⑫、2022年,金九银十我为你准备了《iOS高级资深工程师面试知识总结》 第三方库部分 AFNetworking-SDWebImageView-ReactiveCocoa

    iOS高级资深工程师面试篇系列 - 已更新3篇 UI部分1/3 -UITableView-事件传递&视图响应 UI部分2/3 -图像显示原理-UI卡顿&掉帧 UI部分3/3 -UIVi ...

  6. 【iOS高级资深工程师面试篇】①、2022年,金九银十我为你准备了《iOS高级资深工程师面试知识总结》 UI部分3/3 -UIView绘制原理-离屏渲染

    iOS高级资深工程师面试篇系列 - 已更新3篇 UI部分1/3 -UITableView-事件传递&视图响应 UI部分2/3 -图像显示原理-UI卡顿&掉帧 UI部分3/3 -UIVi ...

  7. 【iOS高级资深工程师面试篇】②、2022年,金九银十我为你准备了《iOS高级资深工程师面试知识总结》 Objective-C语言特性部分1/2 分类-关联对象-扩展-代理

    iOS高级资深工程师面试篇系列 - 已更新3篇 UI部分1/3 -UITableView-事件传递&视图响应 UI部分2/3 -图像显示原理-UI卡顿&掉帧 UI部分3/3 -UIVi ...

  8. 【iOS高级资深工程师面试篇】④、2022年,金九银十我为你准备了《iOS高级资深工程师面试知识总结》 内存管理部分2/2 引用计数-弱引用-自动释放池-循环引用

    iOS高级资深工程师面试篇系列 - 已更新3篇 UI部分1/3 -UITableView-事件传递&视图响应 UI部分2/3 -图像显示原理-UI卡顿&掉帧 UI部分3/3 -UIVi ...

  9. 2020年中高级iOS大厂面试宝典+答案

    前言 过年之后相信有一部分的人,早已磨刀霍霍向大厂.势必要大展拳脚,必将在大厂内创出一片天地.但是,想必大家都知道:最近几年的最严重的互联网寒冬来临,各位兄弟都会说**"江湖再见" ...

最新文章

  1. Oracle XQuery 过滤XML查询SQL
  2. [蓝桥杯][算法提高VIP]盾神与积木游戏(贪心)
  3. 2021年小红书美妆护肤品类行业洞察报告
  4. 带参数的插入语句的问题
  5. 零基础带你学习MySQL—流程控制函数(十七)
  6. python导入turtle报错_由于“未定义宽度错误”,我无法将turtle模块导入Python2.7.10...
  7. MySQL 5.5 日志管理
  8. Java-HashMap实现原理
  9. 计算机网络的分类 ppt,认识计算机网络ppt
  10. linux 消息队列查看和删除
  11. linux下添加4g模块驱动程序,【经验】4G模块SLM750在Linux系统下增加USB串口的详细操作指南...
  12. python--列表、数组扁平化
  13. 图书馆座位预约管理系统毕业设计,图书馆座位管理系统设计与实现,图书馆座位预约系统毕业论文毕设作品参考
  14. 华为平行视界(应用内分屏)
  15. 重点客户销售数据分析python_项目实战 | 使用python分析销售数据
  16. SEO—搜索引擎优化
  17. 传真系统服务器登录不上,cimfax传真服务器设置
  18. 【MATLAB实验】MATLAB图形绘制相关函数与定积分计算
  19. 微信迎来最新改版,做这几款微信插件提高用户体验!
  20. WGCNA与基因模块时空表达分析

热门文章

  1. 程序清单3.3_bases.c程序_《C Primer Plus》P37
  2. DNS 隐蔽通道工具资料汇总
  3. 利用AOP实现对方法执行时间的统计
  4. Fraunhofer ISE多结太阳能电池效率达30.2%
  5. java   web servelt
  6. 深入浅出WPF开发下载
  7. ThreadLocal是否会引发内存泄露的分析 good
  8. Windows Mobile使用Web Service上传和下载二进制数据流
  9. VBScript 之文件 IO 篇
  10. 大推荐——家庭书架·成功读库系列