iOS开发RunLoop

时间:2023-03-09 15:31:13
iOS开发RunLoop

最近处于离职状态,时间也多了起来,但是学习还是不能放松,今天总结一下RunLoop,RunLoop属于iOS系统层的东西,还是比较重要的。

一、什么是RunLoop

字面意思看是跑圈,也可以看作运行循环,我认为RunLoop是个强大的while循环,需要的时候可以将其唤醒工作,不需要的时候可以让其进行休眠节省资源。

那它又有什么作用呢,我总结主要有三点:(1)保持程序的持续运行(2)处理App中的各种事件(比如触摸事件、定时器事件、Selector事件)(3)节省cpu资源,提高程序性能,该做事的时候做事,该休息的时候休息。举个例子,我们程序的入口main函数的UIApplicationMain函数内部久启动了一个RunLoop,所以UIApplicationMain函数一直没有返回,保证了程序的持续运行,默认启动的RunLoop是跟我们主线程相关联的。

二、RunLoop对象

iOS提供了两套API来访问和使用RunLoop:

NSRunLoop(Foundation层)

CFRunLoopRef(Core Foundation层)

三、RunLoop与线程

(1)每条线程都有唯一的一个与之对应的RunLoop对象。

(2)主线程RunLoop已经是创建好的了,子线程的RunLoop需要主动创建。

(3)RunLoop在第一次获取时创建,在线程销毁时销毁,可以将其理解为线程中的变量。

四、RunLoop对象的获取方式

基于Foundation:

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

基于Core Foundation:

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

五、RunLoop相关类

Core Foundation中关于RunLoop的五个类:

(1)CFRunLoopRef

(2)CFRunLoopModeRef

(3)CFRunLoopSourceRef

(4)CFRunLoopTimerRef

(5)CFRunLoopObserverRef

iOS开发RunLoop

RunLoop中可以有多个Mode,是RunLoop的重要组成部分,也是RunLoop中不可缺少的部分,可以理解为如果RunLoop中没有Mode那么RunLoop是跑不起来的。所以说它是不可缺少的部分。其中还包括Source,Timer,Observer。Timer是处理定时器的,Observer可以理解为对RunLoop的监听,不如RunLoop的开启或者休眠等等状态,Source表示所要处理的事情,比如说点击某个按钮处理一些事情都属于Source。我觉得有一点很重要,着重提一下,RunLoop的前提是有Mode,Mode的前提是有Source,Timer,Observer。

下面我们对RunLoop中的相关类做个详细介绍:

1.CFRunLoopModeRef

1.1 CFRunLoopModeRef

(1)CFRunLoopModeRef代表着RunLoop的运行模式。

(2)一个RunLoop包含若干个Mode,每个Mode又包含若干个Source,Timer,Observer。

(3)每次RunLoop启动时,只能指定其中一个Mode,这个Mode被称为CurrentMode。

(4)如果需要切换Mode,只能退出RunLoop,再重新指定一个Mode进入,这样做主要为乐分割Source,Timer,Observer让其互不影响。

1.2 系统会默认注册5个模式:

(1)kCFRunLoopDefaultMode:App默认的Mode,通常主线程是在这个Mode下运行的。

(2)UITrackingRunLoopMode:界面跟踪Mode,用于ScrollerView追踪触摸滑动,保证洁面滑动时不受其他Mode影响。

(3)UIInitializationRunLoopMode:在刚启动app时进入的第一个mode,启动完成后就不在使用。

(4)GSEventReceiveRunLoopMode:接受系统事件的内部mode,通常用不到。

(5)kCFRunLoopCommonModes:这是一个占位用的Mode,不是一种真正的mode,可以理解为不是一个确定的模式,既可以支持(1),又可以支持(2)。比如说我们在处理滑动事件定时器问题,这个mode就是很好的解决办法。

2.CFRunLoopSourceRef 事件源(输入源)

(1)Source0:非基于Port的,Port可以理解为我们的内核,比如说自定的一些事件,自己写的函数。

(2) Source1:基于Port的,相当于系统默认调的函数所产生的事件。

一个RunLoop的执行,在线程栈里会有一些我们看不到的函数是系统调用的。

3.CFRunLoopTimerRef

是基于时间的触发器,基本上说的就是NSTimer。

4.CFRunLoopObserverRef

CFRunLoopObserverRef是观察者,能够监听RunLoop的状态改变,可以监听的时间点有以下几个:

    typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << ), //即将进入RunLoop
kCFRunLoopBeforeTimers = (1UL << ), //即将处理Timer
kCFRunLoopBeforeSources = (1UL << ),//即将处理Sources
kCFRunLoopBeforeWaiting = (1UL << ),//即将进入休眠
kCFRunLoopAfterWaiting = (1UL << ), //刚从休眠中唤醒
kCFRunLoopExit = (1UL << ), //即将退出RunLoop
kCFRunLoopAllActivities = 0x0FFFFFFFU//监听RunLoop的所有情况
};

比如我们想要在按钮点击之前或者点击之后去做一些事情,我们想要监听到这样的一个状态,就可以使用CFRunLoopObserverRef,NSRunLoop中并没有提供CFRunLoopObserverRef的相关接口,我们要使用只能在Core Foundation中使用。

下面通过实例监测下RunLoop的执行状态:

    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, , ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
NSLog(@"activity:%zd",activity);
}); CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
    CFRelease(observer);

打印结果:

-- ::17.268 testRunloop[:] activity:
-- ::17.268 testRunloop[:] activity:
-- ::17.268 testRunloop[:] activity:
-- ::17.270 testRunloop[:] activity:
-- ::17.270 testRunloop[:] activity:
-- ::17.270 testRunloop[:] activity:
-- ::17.270 testRunloop[:] activity:
-- ::17.271 testRunloop[:] activity:
-- ::17.271 testRunloop[:] activity:
-- ::17.271 testRunloop[:] activity:
-- ::17.271 testRunloop[:] activity:
-- ::17.271 testRunloop[:] activity:
-- ::17.271 testRunloop[:] activity:
-- ::17.271 testRunloop[:] activity:
-- ::17.276 testRunloop[:] activity:
-- ::17.276 testRunloop[:] activity:
-- ::17.276 testRunloop[:] activity:
-- ::17.277 testRunloop[:] activity:
-- ::17.277 testRunloop[:] activity:
-- ::17.286 testRunloop[:] activity:
-- ::17.286 testRunloop[:] activity:
-- ::17.286 testRunloop[:] activity:
-- ::17.287 testRunloop[:] activity:
-- ::17.287 testRunloop[:] activity:
-- ::17.287 testRunloop[:] activity:
-- ::17.287 testRunloop[:] activity:
-- ::17.743 testRunloop[:] activity:
-- ::17.744 testRunloop[:] activity:
-- ::17.745 testRunloop[:] activity:
-- ::17.745 testRunloop[:] activity:
-- ::18.699 testRunloop[:] activity:
-- ::18.699 testRunloop[:] activity:
-- ::18.700 testRunloop[:] activity:
-- ::18.700 testRunloop[:] activity:
-- ::22.999 testRunloop[:] activity:
-- ::23.000 testRunloop[:] activity:
-- ::23.000 testRunloop[:] activity:
-- ::23.000 testRunloop[:] activity:

iOS开发RunLoop

现在看这张官方版的逻辑图是不是清晰多了,当然网友的力量是无尽的,下面再给大家展示张网友提供的逻辑图:

iOS开发RunLoop

总结:RunLoop是与线程相对应的,每个线程都会有一个RunLoop,主线程的RunLoop默认是开启的,不需要我们处理,子线程的RunLoop是关闭的,需要我们自己开启,线程开启的时候RunLoop包含mode,而且必须在某个确定的模式下运行,mode里面的Source,Timer,Observer也需要有,还有包括它们所实现的功能等等。

以上就是对RunLoop的最基本的介绍,希望对大家的学习能有所帮助。

注:此文章为原创,转载请注明出处。