Skip to content

一.RunLoop简介

  • 运行循环,实际是一个对象,这个对象在循环中处理程序各种事件(触摸事件、UI刷新事件、定时器事件、Selector事件等),从而保持程序的持续运行
  • Runloop在没有事件处理的时候,会处于睡眠模式,节省CPU资源,提高性能。
  • 如果没有Runloop程序执行时,会立即退出

二.Runloop基本作用

  • 保持程序持续运行: 程序一启动就会启动一个主线程,主线程对应一个Runloop,保证主线程不被销毁,持续运行处理各种事件
  • 处理App中的各种事件:(比如:触摸事件,定时器事件,Selector事件等)
  • 节省CPU资源,提高程序性能: 程序运行起来时,当什么操作都没有做的时候,RunLoop就告诉CPU,现在没有事情做,我要去休息,这时CPU就会将其资源释放出来去做其他的事情,当有事情做的时候RunLoop就会立马起来去做事情

三.RunLoop和线程间的关系

  • 每个线程都有一个与之对应的Runloop对象
  • Runloop保存在一个全局字典里,key是线程,value是Runloop
  • 主线程Runloop已经自动创建好了,子线程需要手动创建
  • Runloop在第一次获取时创建,在线程结束时销毁
  • 具体来说,第一次获取 RunLoop 通常指以下操作之一:
  1. 调用 CFRunLoopGetCurrent()CFRunLoopGetMain() 函数:这两个函数分别返回当前线程或主线程的 CFRunLoop 对象。如果当前线程还没有 RunLoop,系统会在此时创建一个新的 RunLoop 对象。

  2. 调用 NSRunLoop 的类方法 currentRunLoopmainRunLoop:这两个方法分别返回当前线程或主线程的 NSRunLoop 对象。如果当前线程还没有 RunLoop,系统同样会在此时创建一个新的 RunLoop 对象。

  3. 调用某些依赖于 RunLoop 的 API

    • 例如,使用 NSTimer 创建定时器时,定时器会自动添加到当前线程的 RunLoop 中,如果当前线程的 RunLoop 不存在,系统会在此时创建。
    • 使用 performSelector:onThread:withObject:waitUntilDone: 等方法时,系统也会确保目标线程有一个有效的 RunLoop

因此,第一次获取 RunLoop 通常指的是当你在代码中第一次调用与 RunLoop 相关的 API 或方法时,系统会检查当前线程是否已经有一个 RunLoop 对象,如果没有,就会创建一个新的。

总结一下,第一次获取 RunLoop 具体指的是当你在当前线程上首次调用 RunLoop 相关的函数或方法时,系统会在必要时创建并返回一个新的 RunLoop 对象。

四.RunLoop的运行模式

RunLoop的运行模式共有5种,RunLoop只会运行在一个模式下,要切换模式,就要暂停当前模式,重写启动一个运行模式

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

五.Runloop应用

1.常驻线程

如果想要子线程常驻,需要给子线程开启一个Runloop,并且Runloop里至少有一个Timer或者一个Source,防止Runloop停止退出

Objective-C
// 1.创建子线程相关的RunLoop,在子线程中创建即可,并且RunLoop中要至少有一个Timer 或 一个Source 保证RunLoop不会因为空转而退出,因此在创建的时候直接加入
// 添加Source [NSMachPort port] 添加一个端口
[[NSRunLoop currentRunLoop] addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
//添加一个Timer
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(test) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

2.自动释放池

每当一个 runloop 的迭代结束时,会释放与之相关的自动释放池中的所有对象。这意味着,在一个 runloop 迭代中创建的对象,在这次迭代结束时才会被释放。

当RunLoop开启时,就会自动创建一个自动释放池,当RunLoop在休息之前会释放掉自动释放池的东西,然后重新创建一个新的空的自动释放池,当RunLoop退出的时候也会被释放

Objective-C
@autorelease{  
      // 执行代码 
}

世界很美 而你正好有空