Runloop 字面理解为运行循环
作用:
1,保持程序的持续运行。
2,处理程序中的各种事件,比如触摸事件,定时器事件。Selector方法。
3,节省CPU资源,提高程序性能。该做事时做事,该休息时休息(Runloop的状态)
iOS中有两套API访问Runloop
1,Foundation框架
NSRunloop
2,Core Foundation框架
CFRunloopRef
NSRunloop是基于CFRunloopRef的封装
一,runloop与线程的关系
1,每条线程都有唯一的一个与之对应的runloop
2,主线程的runloop已经自动创建好了,子线程的runloop需要主动创建。
3,runloop在第一次获取时创建,在线程结束时销毁。
二,CFRunloopModeRef
CFRunloopModeRef代表Runloop的运行模式
1,一个Runloop包含多个运行模式Mode,每个Mode又包含若干个Source/Timer/Observer。
2,每次Runloop启动时只能启动一个mode,称之为currentmode,可通过此方法获取。
3,如果要切换mode,只能先退出loop,再重新指定一个Mode进入。
系统默认为我们注册了5种运行模式,这里只介绍公开暴露出来的两种
NSDefaultRunLoopMode 默认Mode,通常主线程运行模式。
NSEventTrackingRunLoopMode 界面跟踪Mode,ScrollView追踪滑动触摸,保证界面滑动时不受其他Mode影响。
NSRunLoopCommonModes 标签,被标记的对象可以运行在被标签标记的模式下,随着模式的切换而切换,比如NSTimer。
iOS 中公开暴露出来的只有 NSDefaultRunLoopMode 和 NSRunLoopCommonModes。 NSRunLoopCommonModes 实际上是一个 Mode 的集合,默认包括 NSDefaultRunLoopMode 和 NSEventTrackingRunLoopMode(注意:并不是说Runloop会运行在kCFRunLoopCommonModes这种模式下,而是相当于分别注册了 NSDefaultRunLoopMode和 UITrackingRunLoopMode。当然你也可以通过调用CFRunLoopAddCommonMode()方法将自定义Mode放到 kCFRunLoopCommonModes组合)。
三,CFRunLoopSourceRef
以前分类:
1,Port
2,Custom,Input Source
3,performselector
现在:
1,Source0:
非基于port的,用户主动触发的,如触摸等
2,Source1:
基于Port的,基于内核和其他线程相互发送消息。
四,CFRunLoopObserverRef
CFRunLoopObserver是观察者,可以观察RunLoop的各种状态,并抛出回调。
struct __CFRunLoopObserver {
CFRuntimeBase _base;
pthread_mutex_t _lock;
CFRunLoopRef _runLoop;
CFIndex _rlCount;
CFOptionFlags _activities; /* immutable */
CFIndex _order; /* immutable */
CFRunLoopObserverCallBack _callout; /* immutable */
CFRunLoopObserverContext _context; /* immutable, except invalidation */
};
CFRunLoopObserver可以观察的状态有如下6种:
/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0), //即将进入run loop
kCFRunLoopBeforeTimers = (1UL << 1), //即将处理timer
kCFRunLoopBeforeSources = (1UL << 2),//即将处理source
kCFRunLoopBeforeWaiting = (1UL << 5),//即将进入休眠
kCFRunLoopAfterWaiting = (1UL << 6),//被唤醒但是还没开始处理事件
kCFRunLoopExit = (1UL << 7),//run loop已经退出
kCFRunLoopAllActivities = 0x0FFFFFFFU
};
什么是Runloop?
字面意思是一个运行循环,其实内部是一个do while 循环,在处理各种事件,timer,source,Observer。
一个线程对应一个Runloop。主线程自动启动,子线程需要手动启动,调用Run方法。
Runloop只能选择一个模式启动,更改模式需要先退出再进入新模式。如果Model没有任何timer。source,那么直接退出runloop。
自动释放池什么时候释放?
根据Observer观察的Runloop状态释放,runloop退出。
五,Runloop应用
1,NSTimer
定时器设置为CommonMode更精准
2,ImageVIew显示
将图片的显示设置在UITracking模式,可以保证在列表滑动的时候依然能够加载视图。
3,PerformSeletor
4,常驻线程
创建一个Runloop在子线程一直运行,保证线程在后台常驻(AFNetworking源码)。
子线程的Runloop需要手动调用,然后添加一个Source或者Timer事件,再调用Run方法。
5,自动释放池
Runloop内部会自动创建一个自动释放池,开始的时候创建,等到合适的时机再释放,通过观察Runloop状态来进行。
6,通过对Runloop添加Observer来做一些事情
(1),比如监听点击事件,当runloop处理点击事件时候可以统一做一些事情。
(2),也可以通过对Runloop状态的观察来检测系统卡顿,当长时间处于一个模式不变就是出现了卡顿。
//创建子线程监控
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//子线程开启一个持续的 loop 用来进行监控
while (YES) {
long semaphoreWait = dispatch_semaphore_wait(dispatchSemaphore, dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC));
if (semaphoreWait != 0) {
if (!runLoopObserver) {
timeoutCount = 0;
dispatchSemaphore = 0;
runLoopActivity = 0;
return;
}
//BeforeSources 和 AfterWaiting 这两个状态能够检测到是否卡顿
if (runLoopActivity == kCFRunLoopBeforeSources || runLoopActivity == kCFRunLoopAfterWaiting) {
//将堆栈信息上报服务器的代码放到这里
} //end activity
}// end semaphore wait
timeoutCount = 0;
}// end while
});