对iOS中RunLoop的归纳总结

首先对于RunLoop这个概念,大家都听过,但对其认识都是比较抽象的,只知道其存在于遥远的main函数中,而在开发中如何合理使用runloop,以及对runloop的基本数据类型与定义都不是很清楚,这篇文章就总结一下自己对于runloop的理解。

在iOS开发中,runloop是一个通过事件循环来对消息或者事件进行管理的一个对象,在没有消息需要处理时,进行休眠以避免资源浪费,在有消息需要被处理时立即唤醒,进行消息与事件的处理。总而言之其就是一个神经中枢,在没有事情做的时候进行休眠,有事情做的时候就醒来做事,做完事又继续睡觉,比较像一天的上班时间,哈哈。

而在runloop实现事件循环的过程中,状态切换做了怎么样的操作呢。

当没有消息处理时,runloop进入休眠状态,这时将当前线程的控制权由用户态交给内核态控制。而当有消息需要处理时,runloop被唤醒,这时线程的控制权由内核态转交给用户态。

那么什么是用户态和内核态呢,我们可以理解为,我们开发中使用的API大多都是用户态的API,用户态的API不会接触到太底层的系统机制调用,如中断、关机等,介于安全因素考虑,开发中一般不会涉及到相应的操作,所以这些相应的系统层级操作都交由内核态管理。

最常见的runloop调用就是在项目main函数中的UIApplicationMain方法的调用中了,其工作原理就是1.接收消息,2.处理消息,3.等待。等待就是进行自我休眠,而这里所谓的等待也绝不仅是一个死循环这么简单,文章后续会详细讲到。

关于runLoop在OC中系统给我们提供了两套API,一套是NSRunLoop,另一套是CFRunLoop,两套API中CFRunLoop更偏向底层一些,而NSRunLoop是对CFRunLoop的一次封装,提供了面向对象思想的API,其所属框架也不同,NSRunLoop存在于Foundation框架中,而CFRunLoop存在于Core Foundation框架中。而在于这两套API中,主要的数据结构有三种:

1.CFRunLoop顾名思义代表的是一个runloop对象,2.CFRunLoopMode代表的就是runloop中的对应模式,3.Source/Time/Observer,代表的就是在runloop每个模式下的三种类型对象。

接下来探究一下CFRunLoop之中的内容:

1.pthread,代表了runloop与线程一一对应的关系,表明当前runloop在哪条线程里

2.currentMode,表明当前runloop模式,是CFRunLoopMode类型的数据结构。

3.modes,表明存在于当前runloop中的mode类型集合,是CFRunLoopMode类型的集合

4.commenModes,是对于一些runLoopMode的标识,被标识的runLoopMode存在与commenRunLoopModes当中,其是一个字符串类型的集合。从而可以看出,CFRunLoopMode其实也是对特殊的字符串进行的类型重写,其本质就是NSString类型的。

5.commenModeItems,这也是一个集合类型的数据类型,其中装了很多Source,Timer和Observer,表明的是被标明的特定的一些CFRunLoopMode中共同存有的这些Source/Timer/Observer。

熟悉了CFRunLoop之中的内容后,我们梳理一下CFRunLoopMode之中的内容:

1.name,表明当前mode的名称

2.source0,不具备唤醒当前runloop线程能力的source,需要手动唤醒当前线程。集合类型

3.source1,具备唤醒当前runloop线程能力的source,集合类型

4.timer,计时器,数组类型

5.observer,观察者,数组类型

以上的数据结构内容可以看出,CFRunLoopMode中包含了其模式中所存放的source/timer/observer。

所以综上所述,可以理解一个runloop对象,首先包含了相应的线程信息,其次包含了其中所有的模式分隔,以及模式中所对应的source/timer/observer,然后其中还包含了一种特殊的标识模式commenModes,以及commenModes中对应的items,这样对于一个runloop对象的理解,就清晰了许多了。

其次再讨论一下observer观察者的6个观察时间点:

1.kCFRunLoopEntry,表明一个runloop即将启动的时候

2.kCFRunLoopBeforeTimers,表明runloop即将处理timer相关的事件

3.kCFRunLoopBeforeSources,表明runloop即将处理source相关的事件

4.kCFRunLoopBeforeWaiting,表明runloop即将进入休眠状态,也是用户态即将切换为内核态的时机

5.kCFRunLoopAfterWaiting,表明runloop已经被唤醒,也是内核态已经切换为用户态不久的时机

6.kCFRunLoopExit,表明runloop已经退出的时间点

 

从上面的梳理可以看出线程与runloop是一一对应的关系,而runloop与其内部的mode是一对多的关系,mode与其中所包含的source/timer/observer事件也是一对多的关系。在runloop的每种模式中,其事件的相应都是互不影响,互相独立的,比如runloop运行在mode1上,这时mode2出现一个事件的回调,这个时候mode2上的这个回调是拿不到的,必须等待runloop运行到mode2时,才能拿到事件的回调,这也起到了一个mode之间互相屏蔽的作用。

在runloop中一共有5种模式的mode,分别为:

1.Default模式

2.Connection模式

3.Modal模式

4.Event tracking模式

5.Common模式

它们分别处理不同类型的事件与回调,但需要注意的是,最后一种mode——commonMode不是一种真正的mode,而是一种特定的标识类型mode,是一种同步source/timer/observer到多种模式中的一种技术方案。在其标识的类型mode中,添加事件处理意味着在其中的模式中均可以处理事件的回调,一般默认的commenmode中包含有defalt模式,tracking模式还有modal模式,可使用CFRunLoopAddCommenMode方法向Common Modes中添加自定义modes。

下面来整体梳理一下runloop事件处理机制的整体流程:

1.首先即将创建runloop时,会给相应的observer发送一个消息,告诉其时间点将要进入runloop了

2.其次将要处理timer以及source0事件时同样会给observer发送观察消息,告诉事件节点将要处理timer以及source事件

3.处理timer与source0事件

4.如果有source1事件处理,则使用goto语句进行下一步操作跳转,直接处理唤醒时收到的消息,随后返回步骤2,进行重复操作。

5.如果没有source1事件进行处理,那么runloop就即将进入休眠状态了,此时给observer发送消息,表明beforeWaiting,即将进入休眠状态,随后线程进入休眠

6.如果此时有source1事件,或者timer事件或者外部唤醒事件的产生,runloop就会被唤醒,随后发送消息给observer,表明线程已经被唤醒,afterWaiting,随后处理唤醒时收到的消息,随后回到步骤2进行重复。

7.当线程将要退出或者程序即将要退出的时候,会给observer发送一个runloopExit的消息,表明runloop即将退出,程序即将销毁了,随后退出runloop,进行线程销毁。

综上所述,当一个程序的启动——>运行——>再到结束的生命周期也是如此:程序在main函数中调用UIApplicationMain方法,对主线程开启一个runloop,此时runloop对象给观察者发送消息,表明即将开启runloop,并且处理timer以及source对象,一并发送消息,随后判断是否有source1事件,是的话就直接进行唤醒操作,处理source1事件,随后重复之前第二步,之后如果没有source1类型的事件则发送消息给observer,runloop进行休眠。此时如果有触摸事件等source1类型的事件,或timer事件或手动唤醒runloop事件的发生,则进行线程唤醒,并且处理唤醒消息,之后再次重复步骤2,至线程休眠。当程序即将被销毁的时候,runloop执行退出操作,给observer发送观察消息,销毁线程,退出runloop,退出程序。结束了一次程序生命周期。runloop的核心就是runloop从唤醒到休眠状态的改变,从用户态切换为内核态,而从休眠到唤醒是从内核态转变为用户态的过程。

那么怎样利用runloop和NSTread配合实现一个常驻线程呢,首先我们需要知道的一点是,当我们手动创建一个子线程的时候,是不会给子线程添加runloop的,所以我们需要手动添加。

1.手动创建一条子线程

2.给子线程手动添加一个runloop对象以及给runloop对象添加一个source事件维持事件循环,否则runloop一添加就进入睡眠状态了。

3.启动runloop。

详细的源码我稍后会放在我的gayhub上。

关于runloop的总结就总结到这里了,之后如果还有想到的我会继续补充上来。

 

本文章由作者原创,未经允许禁止转载

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值