iOS Runloop

runloop是线程相关底层基础的一部分, 作用是接受循环事件和安排线程工作, 让线程有任务的时候工作, 而没有任务的时候处于休眠状态

runloop作用
  1. 保持程序持续运行
  2. 处理app中的各种事件
  3. 节省CPU资源, 提高程序性能
runloop和线程关系
  • 每条线程都有唯一的Runloop对象
  • 主线程的Runloop对象自动创建, 子线程的runloop需要主动创建
  • runloop在第一次获取时创建, 在线程结束时销毁
创建runloop
  • 通过[NSRunloop currentRunLoop]创建一个线程的runloop

原因】:currentRunLoop 本身是懒加载的,当第一次调用currentRunLoop 方法获得该子线程对应的 Runloop 的时候,它会先去判断(去字典中查找)这个线程的Runloop 是否存在,如果不存在就会自己创建并且返回,如果存在直接返回。

获取runloop
  // Foundation框架
    NSRunLoop *mainRunloop = [NSRunLoop mainRunLoop]; // 获得主线程对应的 runloop对象
    NSRunLoop *currentRunloop = [NSRunLoop currentRunLoop]; // 获得当前线程对应的runloop对象
    
    // Core Foundation框架
    CFRunLoopRef maiRunloop = CFRunLoopGetMain(); // 获得主线程对应的 runloop对象
    CFRunLoopRef maiRunloop = CFRunLoopGetCurrent(); // 获得当前线程对应的runloop对象
Runloop相关类
  • CFRunloopRef: RunLoop本身
  • CFRunLoopModeRef: runloop运行模式
    1. 【kCFRunLoopDefaultMode(NSDefaultRunLoopMode)】:App的默认Mode,通常主线程是在这个Mode下运行。
    2. UITrackingRunLoopMode】: 界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响。
    3. 【UIInitializationRunLoopMode】: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用。
    4. 【GSEventReceiveRunLoopMode】: 接受系统事件的内部 Mode,通常用不到。
    5. kCFRunLoopCommonModes (NSRunLoopCommonModes)】: 这个并不是某种具体的 Mode, 可以说是一个占位用的Mode(一种模式组合)。
  • CFRunloopSourceRef: runloop要处理的事件源
    1. Source0:非基于端口Port的事件;(用于用户主动触发的事件,如:点击按钮 或点击屏幕)
    2. Source1:基于端口Port的事件;(通过内核和其他线程相互发送消息,与内核相关)。
  • CFRunloopTimerRed: Timer事件(基于时间的触发器)
    1. NSTimer会受到Runloop的mode影响
    2. 与NSTimer相比, GCD定时器不会受到Runloop影响
  • CFRunLoopObserverRef: runloop观察者

相当于消息循环的一个监听器, 随时通知外部当前Runloop的运行状态

typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0),           //即将进入Runloop
    kCFRunLoopBeforeTimers = (1UL << 1),    //即将处理NSTimer
    kCFRunLoopBeforeSources = (1UL << 2),   //即将处理Sources
    kCFRunLoopBeforeWaiting = (1UL << 5),   //即将进入休眠
    kCFRunLoopAfterWaiting = (1UL << 6),    //从休眠装填中唤醒
    kCFRunLoopExit = (1UL << 7),            //退出runloop
    kCFRunLoopAllActivities = 0x0FFFFFFFU   //所有状态改变
};
Runloop应用/场景
  1. NSTimer
  2. ImageView显示: 控制方法在特定模式下可用
  3. performSelector
  4. 常驻线程: 在子线程中开启一个runloop
  5. AutoreleasePool自动释放池
  6. UI更新
runloop面试题

Q:runloop是来做什么的?runloop和线程有什么关系?主线程默认开启了runloop么?子线程呢?

A:runloop: 从字面意思看:运行循环、跑圈,其实它内部就是do-while循环,在这个循环内部不断地处理各种任务(比如Source、Timer、Observer)事件。runloop和线程的关系:一个线程对应一个RunLoop,主线程的RunLoop默认创建并启动,子线程的RunLoop需手动创建且手动启动(调用run方法)。RunLoop只能选择一个Mode启动,如果当前Mode中没有任何Source(Sources0、Sources1)、Timer,那么就直接退出RunLoop。

Q:runloop的mode是用来做什么的?有几种mode?

A:model:是runloop里面的运行模式,不同的模式下的runloop处理的事件和消息有一定的差别。系统默认注册了5个Mode:(1)kCFRunLoopDefaultMode: App的默认 Mode,通常主线程是在这个 Mode 下运行的。(2)UITrackingRunLoopMode: 界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响。(3)UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用。(4)GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到。(5)kCFRunLoopCommonModes: 这是一个占位的 Mode,没有实际作用。注意iOS 对以上5中model进行了封装 NSDefaultRunLoopMode、NSRunLoopCommonModes

Q:为什么把NSTimer对象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)添加到主运行循环以后,滑动scrollview的时候NSTimer却不动了?

A nstime对象是在 NSDefaultRunLoopMode下面调用消息的,但是当我们滑动scrollview的时候,NSDefaultRunLoopMode模式就自动切换到UITrackingRunLoopMode模式下面,却不可以继续响应nstime发送的消息。所以如果想在滑动scrollview的情况下面还调用nstime的消息,我们可以把nsrunloop的模式更改为NSRunLoopCommonModes.

Q:苹果是如何实现Autorelease Pool的?

A: Autorelease Pool作用:缓存池,可以避免我们经常写relase的一种方式。其实就是延迟release,将创建的对象,添加到最近的autoreleasePool中,等到autoreleasePool作用域结束的时候,会将里面所有的对象的引用计数器 - autorelease.

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容