一.RunLoop简介
- 运行循环,实际是一个对象,这个对象在循环中处理程序各种事件(触摸事件、UI刷新事件、定时器事件、Selector事件等),从而保持程序的持续运行
- Runloop在没有事件处理的时候,会处于睡眠模式,节省CPU资源,提高性能。
- 如果没有Runloop程序执行时,会立即退出
二.Runloop基本作用
- 保持程序持续运行: 程序一启动就会启动一个主线程,主线程对应一个Runloop,保证主线程不被销毁,持续运行处理各种事件
- 处理App中的各种事件:(比如:触摸事件,定时器事件,Selector事件等)
- 节省CPU资源,提高程序性能: 程序运行起来时,当什么操作都没有做的时候,RunLoop就告诉CPU,现在没有事情做,我要去休息,这时CPU就会将其资源释放出来去做其他的事情,当有事情做的时候RunLoop就会立马起来去做事情
三.RunLoop和线程间的关系
- 每个线程都有一个与之对应的Runloop对象
- Runloop保存在一个全局字典里,key是线程,value是Runloop
- 主线程Runloop已经自动创建好了,子线程需要手动创建
- Runloop在第一次获取时创建,在线程结束时销毁
- 具体来说,第一次获取
RunLoop通常指以下操作之一:
调用
CFRunLoopGetCurrent()或CFRunLoopGetMain()函数:这两个函数分别返回当前线程或主线程的CFRunLoop对象。如果当前线程还没有RunLoop,系统会在此时创建一个新的RunLoop对象。调用
NSRunLoop的类方法currentRunLoop或mainRunLoop:这两个方法分别返回当前线程或主线程的NSRunLoop对象。如果当前线程还没有RunLoop,系统同样会在此时创建一个新的RunLoop对象。调用某些依赖于
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{
// 执行代码
}