iOS runLoop 原理多线程 总结 NSTimer优化

本文介绍了iOS中的RunLoop原理,包括它的运行机制、线程关系和与NSTimer的配合使用。文章详细阐述了RunLoop的运行模式、相关类以及它们之间的关系,并提供了实际操作示例,如NSTimer在不同运行模式下的表现,以及如何保持子线程常驻内存。此外,还讨论了RunLoop在实战中的应用,如NSTimer的优化、ImageView推迟显示和后台常驻线程的实现。
摘要由CSDN通过智能技术生成

1. RunLoop 简介

1.1 什么是 RunLoop?

 


可以理解为字面意思:Run 表示运行,Loop 表示循环。结合在一起就是运行的循环的意思。哈哈,我更愿意翻译为『跑圈』。直观理解就像是不停的跑圈。

RunLoop 实际上是一个对象,这个对象在循环中用来处理程序运行过程中出现的各种事件(比如说触摸事件、UI刷新事件、定时器事件、Selector事件),从而保持程序的持续运行。

RunLoop 在没有事件处理的时候,会使线程进入睡眠模式,从而节省 CPU 资源,提高程序性能。

1.2 RunLoop 和线程

 


RunLoop 和线程是息息相关的,我们知道线程的作用是用来执行特定的一个或多个任务,在默认情况下,线程执行完之后就会退出,就不能再执行任务了。这时我们就需要采用一种方式来让线程能够不断地处理任务,并不退出。所以,我们就有了 RunLoop。

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

  2. RunLoop 并不保证线程安全。我们只能在当前线程内部操作当前线程的 RunLoop 对象,而不能在当前线程内部去操作其他线程的 RunLoop 对象方法。

  3. RunLoop 对象在第一次获取 RunLoop 时创建,销毁则是在线程结束的时候。

  4. 主线程的 RunLoop 对象系统自动帮助我们创建好了(原理如 1.3 所示),而子线程的 RunLoop对象需要我们主动创建和维护。

1.3 默认情况下主线程的 RunLoop 原理

 


我们在启动一个iOS程序的时候,系统会调用创建项目时自动生成的 main.m 的文件。main.m文件如下所示:

1

2

3

4

5

int main(int argc, char * argv[]) {

    @autoreleasepool {

        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));

    }

}

其中 UIApplicationMain 函数内部帮我们开启了主线程的 RunLoop,UIApplicationMain 内部拥有一个无限循环的代码,只要程序不退出/崩溃,它就一直循环。上边的代码中主线程开启 RunLoop 的过程可以简单的理解为如下代码:

1

2

3

4

5

6

7

8

int main(int argc, char * argv[]) {        

    BOOL running = YES;

    do {

        // 执行各种任务,处理各种事件

        // ......

    while (running);  // 判断是否需要退出

    return 0;

}

从上边可看出,程序一直在 do-while 循环中执行,所以 UIApplicationMain 函数一直没有返回,我们在运行程序之后程序不会马上退出,会保持持续运行状态。

下图是苹果官方给出的 RunLoop 模型图。

image.png

从上图中可以看出,RunLoop 就是线程中的一个循环,RunLoop 会在循环中会不断检测,通过 Input sources(输入源)和 Timer sources(定时源)两种来源等待接受事件;然后对接受到的事件通知线程进行处理,并在没有事件的时候让线程进行休息。

2. RunLoop 相关类

 


下面我们来了解一下Core Foundation框架下关于 RunLoop 的 5 个类,只有弄懂这几个类的含义,我们才能深入了解 RunLoop 的运行机制。

  1. CFRunLoopRef:代表 RunLoop 的对象

  2. CFRunLoopModeRef:代表 RunLoop 的运行模式

  3. CFRunLoopSourceRef:就是 RunLoop 模型图中提到的输入源 / 事件源

  4. CFRunLoopTimerRef:就是 RunLoop 模型图中提到的定时源

  5. CFRunLoopObserverRef:观察者,能够监听 RunLoop 的状态改变

下边详细讲解下几种类的具体含义和关系。

先来看一张表示这 5 个类的关系图帮助理解(来源:blog.ibireme.com/2015/05/18/…)。

image.png

接着来讲解这 5 个类的相互关系:

一个RunLoop对象(CFRunLoopRef)中包含若干个运行模式(CFRunLoopModeRef)。而每一个运行模式下又包含若干个输入源(CFRunLoopSourceRef)、定时源(CFRunLoopTimerRef)、观察者(CFRunLoopObserverRef)。

  • 每次 RunLoop 启动时,只能指定其中一个运行模式(CFRunLoopModeRef),这个运行模式(CFRunLoopModeRef)被称作当前运行模式(CurrentMode)。

  • 如果需要切换运行模式(CFRunLoopModeRef),只能退出当前 Loop,再重新指定一个运行模式(CFRunLoopModeRef)进入。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值