写在前面
文章是对网络上的一些讲解做了自己的整理,方便自己理解。
概念
什么是RunLoop?
RunLoop是什么?为什么要有RunLoop?一般来说,一个线程只能执行一个任务,执行完就退出。如果我们需要一种机制,让线程不退出,随时能处理事件,那么我们就用到了RunLoop。
RunLoop又称之为运行循环,内部就是一个do-while循环(可以这么理解,但是实际上是用户状态的改变)。在这个循环内部不断的处理各种事务,保证程序持续运行。RunLoop存在的目的就是当线程中有任务的时候,保证线程干活,当线程没有任务的时候,让线程睡眠,提高程序性能,节省资源,该做事的时候做事,该休息的时候休息。
用户状态改变:
在mian函数,也就是APP启动之后生成了一个runloop,这个runloop并不是死循环,事件处理实际上是用户状态的改变。当有事件的时候,处理事件,内核态转换为用户态。当没有事件处理的时候,用户态转换为内核态。
作用
1、保持程序持续运行
App一启动就会开启主线程,主线程在开启的时候就会开启主线程对应的RunLoop,RunLoop能保证线程不被销毁,主线程不销毁,程序就会持续运行。
2、处理App中各类事件
事件响应、手势识别、界面刷新、AutoreleasePool自动释放池、NSTimer等事件处理。
3、节省CPU资源,提高程序性能
如概述所述,当线程中有任务的时候,保证线程干活,当线程没有任务的时候,让线程睡眠,提高程序性能,节省资源,该做事的时候做事,该休息的时候休息。
深入理解
先有线程 然后才会有runloop【重要】
1.一个runloop 包含若干个mode,当启动一个runloop时会先指定一个mode。检查指定的mode是否存在或者mode是否包含 source和timer,如果不存在就说明是一个空的mode,然后runloop直接退出。
2.runloop 官方模型图
一个runloop包含 input sources 和 timer sources,通过这个两个来源接受事件到线程中去处理,在没有事件的时候让线程休息。
3.Core Foundation 框架的关于runloop的5个类
CFRunLoopRef:代表runloop对象
- Core Foundation框架获取runloop
CFRunLoopGetCurrent();// 获取当前线程的runloop
CFRunLoopGetMain();// 获取主线程runloop
- Foundation框架获取runloop
[NSRunLoop currentRunLoop];
[NSRunLoop mainRunLoop];
CFRunLoopModeRef:代表runloop运行模式
系统默认定义了多种运行模式:(前面三种是开发中用到的模式)
- kCFRunLoopDefaultMode 【APP的默认模式,主线程中在这个模式下运行】
- UITrackingRunLoopMode 【跟踪用户交互事件,例如在scrollView滚动的时候,】
- kCFRunLoopCommonModes 【伪模式,不是一种真正的模式】
- UIInitializationRunLoopMode 【在刚启动APP时进入第一个mode,启动完成后就不再使用】
- GSEventReceiveRunLoopMode【接收系统内部事件,通常用不到】
CFRunLoopSourceRef:代表模型中的输入源/事件源
- Port-Based Sources(基于端口)
- Custom Input Sources(自定义)
- Cocoa Perform Selector Sources
CFRunLoopTimerRef:定时源
- NSTimer
CFRunLoopObserverRef:观察者监听Runloop状态变化
CFRunLoopObserverRef是观察者,用来监听RunLoop的状态改变,CFRunLoopObserverRef可以监听的状态改变有以下几种:
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0), // 即将进入Loop:1
kCFRunLoopBeforeTimers = (1UL << 1), // 即将处理Timer:2
kCFRunLoopBeforeSources = (1UL << 2), // 即将处理Source:4
kCFRunLoopBeforeWaiting = (1UL << 5), // 即将进入休眠:32
kCFRunLoopAfterWaiting = (1UL << 6), // 即将从休眠中唤醒:64
kCFRunLoopExit = (1UL << 7), // 即将从Loop中退出:128
kCFRunLoopAllActivities = 0x0FFFFFFFU // 监听全部状态改变
};