RunLoop

简介: 简介什么是 RunLoop ?从字面意思看的话是运行循环、跑圈的意思;RunLoop 的基本作用是什么:保持程序的持续运行;处理 App 中的各种事件(比如触摸事件、定时器事件、Selector 事件);节省 CPU 资源,提高程序性能:...

简介

什么是 RunLoop ?

从字面意思看的话是运行循环、跑圈的意思;

RunLoop 的基本作用是什么:
  • 保持程序的持续运行;
  • 处理 App 中的各种事件(比如触摸事件、定时器事件、Selector 事件);
  • 节省 CPU 资源,提高程序性能:该做事时做事,该休息时休息;
如果没有RunLoop
int main(int argc, char * argv[])
{
    // 程序开始
    NSLog(@"execute main function");
    // 程序结束
    return 0;
}

没有 RunLoop 的情况下:第3行后程序就结束了;

如果有了RunLoop
int main(int argc, char * argv[]) 
{
    BOOL running = YES;
    do 
        {
            // 执行各种任务,处理各种事件
           // ......
        } while (running);
    return 0;
}

有 RunLoop 的情况下:由于 main 函数里面启动了个 RunLoop ,所以程序并不会马上退出,保持持续运行状态

main函数中的RunLoop
int main(int argc, char * argv[])
{
    @autoreleasepool
    {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

第 5 行代码的 UIApplicationMain 函数内部就启动了一个 RunLoop 所以 UIApplicationMain 函数一直没有返回,保持了程序的持续运行。这个默认启动的 RunLoop 是跟主线程相关联的;

RunLoop对象

iOS 中哪些 API 来访问和使用 RunLoop?
  • Foundation
    NSRunLoop
  • Core Foundation
    CFRunLoopRef

NSRunLoop 和 CFRunLoopRef 都代表着 RunLoop 对象;

NSRunLoop 是基于 CFRunLoopRef 的一层 OC 包装,所以要了解RunLoop内部结构,需要多研究CFRunLoopRef层面的API(Core Foundation层面);

RunLoop资料
RunLoop与线程
  • 每条线程都有唯一的一个与之对应的 RunLoop 对象;
  • 主线程的 RunLoop 已经自动创建好了,子线程的 RunLoop 需要主动创建;
  • RunLoop 在第一次获取时创建,在线程结束时销毁;
获得 RunLoop 对象
  • Foundation
// 获得当前线程的RunLoop对象
[NSRunLoop currentRunLoop]; 
// 获得主线程的RunLoop对象
[NSRunLoop mainRunLoop]; 
  • Core Foundation
// 获得当前线程的RunLoop对象
CFRunLoopGetCurrent(); 
 // 获得主线程的RunLoop对象
CFRunLoopGetMain();

RunLoop相关类

Core Foundation 中有几个关于RunLoop的类?

Core Foundation 中有5个关于RunLoop的类;

  • CFRunLoopRef
  • CFRunLoopModeRef
  • CFRunLoopSourceRef
  • CFRunLoopTimerRef
  • CFRunLoopObserverRef
img_58ecbdecc95fed00607db45da77ee57a.png
RunLoop
CFRunLoopModeRef
  • CFRunLoopModeRef 代表 RunLoop 的运行模式;
  • 一个 RunLoop 包含若干个 Mode,每个 Mode 又包含若干个Source/Observer/Timer;
  • 每次 RunLoop 启动时,只能指定其中一个 Mode,这个 Mode 被称作 CurrentMode;
  • 如果需要切换 Mode,只能退出 Loop,再重新指定一个 Mode 进入
  • 这样做主要是为了分隔开不同组的 Source/Observer/Timer,让其互不影响;
RunLoop 中有几种 Mode?

系统默认注册了 5 种 Mode;

  • kCFRunLoopDefaultMode:App 的默认 Mode ,通常主线程是在这个 Mode 下运行;
  • UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响;
  • UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode ,启动完成后就不再使用;
  • GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode ,通常用不到;
  • kCFRunLoopCommonModes: 这是一个占位用的 Mode ,不是一种真正的Mode;
CFRunLoopSourceRef

CFRunLoopSourceRef 是事件源(输入源)

  • 按照 Apple 官方文档 Sources 的分类:
    Port-Based Sources
    Custom Input Sources
    Cocoa Perform Selector Sources

  • 按照函数调用栈 Sources 的分类:
    Source0:非基于 Port;
    Source1:基于 Port,通过内核和其他线程通信,接受,分发系统事件;

CFRunLoopTimerRef

CFRunLoopTimerRef 是基于时间的触发器;
基本上说的就是 NSTimer;

CFRunLoopObserverRef

CFRunLoopObserverRef 是观察者,能够监听 RunLoop 的状态改变;

可以监听的时间点有以下几个

typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) 
{
    // 即将进入 RunLoop
    kCFRunLoopEntry = (1UL << 0) = 1,
    // 即将处理 Timer
    kCFRunLoopBeforeTimers = (1UL << 1) = 2,
    // 即将处理 Source
    kCFRunLoopBeforeSources = (1UL << 2) = 4,
    // 即将进入 睡眠
    kCFRunLoopBeforeWaiting = (1UL << 5) = 32,
    // 刚从 睡眠 中 唤醒
    kCFRunLoopAfterWaiting = (1UL << 6) = 64,
    // 即将退出 RunLoop
    kCFRunLoopExit = (1UL << 7) = 128,
    // 所有活动
    kCFRunLoopAllActivities = 0x0FFFFFFFU
};

RunLoop 处理逻辑

官方版
img_f393cb97bdc4cc0cffe669d74cce93f6.png
官方版 RunLoop 处理逻辑
img_454b1e55831f9a90e84978f53f816343.png
官方版 RunLoop 处理逻辑
网友整理版
img_da20a20dc90e6625643f9d7c35f0da7a.png
网友整理版 RunLoop 处理逻辑

RunLoop 应用

  • NSTimer
  • ImageView显示
  • PerformSelector
  • 常驻线程
  • 自动释放池
目录
相关文章
|
3月前
|
安全 Java
如何停止线程?
【8月更文挑战第8天】如何停止线程?
63 0
C#深入理解AutoResetEvent和ManualResetEvent
当在C#使用多线程时就免不了使用AutoResetEvent和ManualResetEvent类,可以理解这两个类可以通过设置信号来让线程停下来或让线程重新启动,其实与操作系统里的信号量很相似(汗,考完考试已经有点忘记了)。
1929 0