一、RunLoop是什么?
事件循环,绝对不止是死循环这么简单的一个回答。实质上就是runloop内部状态的转换。
1.用户态:应用程序都是在用户态,平时开发用到的api等都是用户态的操作
2.内核态:系统调用,牵涉到操作系统,底层内核相关的指令。
runloop实际上是计算机内部进行的资源调度操作。
iOS中的runloop就是循环来处理程序运行过程中出现的各种事件(比如说触摸事件、UI刷新事件、定时器事件、Selector事件),从而保持程序的持续运行,而在没有任何任务处理时,会让线程休眠,从而节省 CPU 资源,提高程序性能。
iOS中的runloop是用来处理事件的循环,NSRunloop是基于CFRunloop的封装,是线程不安全的;CFRunloop是一套C接口,是线程安全的。
二、runloop有哪些使用场景?
1,检测crash,crash的起死回生;
2,线程的耦合;
3,监测APP的卡顿;
4,线程保活(让线程长时间存活,而不被自动销毁掉)等。
三,runloop的组成?
CFRunLoopRef //runloop对象包含以下内容:
CFRunLoopModeRef//运行模式
CFRunLoopObserverRef
CFRunLoopTimerRef
CFRunLoopSourceRef//sources源(事件源)
sources包含source0和source1,
source1:是基于Port的系统内核事件,主动唤醒,是基于字典的(key?-value?)。
source0:是非基于Port的,是用户事件,不能主动触发,需要手动唤醒(weakup),事件源一般存放在数组中,
runloop要想正常启动,需要添加一个source源,或者一个timer,有三种当方式:addPort,addTimer,CFRunloopAddSource。
四,runloop与线程的关系?
线程与runloop是一一对应关系,由runloop的foundation的CFRunloopGet0源码可以看出,线程与runloop是以键值对的形式存储,key值存当前线程,value值存与线程对应的runloop。
1,(线程与runloop是一一对应关系)一条线程对应一个RunLoop对象,每条线程都有唯一一个与之对应的 RunLoop 对象。
RunLoop 并不保证线程安全。我们只能在当前线程内部操作当前线程的 RunLoop 对象,而不能在当前线程内部去操作其他线程的 RunLoop 对象方法。
2,RunLoop 对象在第一次获取 RunLoop 时创建,销毁则是在线程结束的时候。
3,主线程的 RunLoop 对象系统自动帮助我们创建好了(原理如 1.3 所示),而子线程的 RunLoop对象需要我们主动创建和维护。
五,主线程需要保活吗?
子线城需要事件源,线程才能保活。
主线程不需要,(值为1)底层源码分析得。
六,runloop如何启动?,启动方式有哪些?
三种方式:run,runUntilDate,RunMode:beforDate。
前两种底层其实是无限循环调用RunMode方法,使用后runloop不会停止,故一般使用第三种,启动一次runloop,调用停止runloop方法后,便可结束runloop。
七,如何停止runloop?
CFRunLoopStop
若用strong修饰thread,需将thread设置为nil。
ViewController释放后,也需要需将thread设置为nil,防止内存泄露。
八,runloop原理?
在每次运行开启RunLoop的时候,所在线程的RunLoop会自动处理之前未处理的事件,并且通知相关的观察者。
具体的顺序如下:
通知观察者RunLoop已经启动
通知观察者即将要开始的定时器
通知观察者任何即将启动的非基于端口的源
启动任何准备好的非基于端口的源
如果基于端口的源准备好并处于等待状态,立即启动;并进入步骤9
通知观察者线程进入休眠状态
将线程置于休眠知道任一下面的事件发生:
某一事件到达基于端口的源
定时器启动
RunLoop设置的时间已经超时
RunLoop被显示唤醒
通知观察者线程将被唤醒
处理未处理的事件
如果用户定义的定时器启动,处理定时器事件并重启RunLoop。进入步骤2
如果输入源启动,传递相应的消息
如果RunLoop被显示唤醒而且时间还没超时,重启RunLoop。进入步骤2
通知观察者RunLoop结束。