OC底层基础:RunLoop

查看oc文件底层结构

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc xxx.m

支持ARC、指定运行时系统版本

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-15.0.0 xxx.m

一、RunLoop基础

1. RunLoop对象

  • iOS中有两套API来访问和使用RunLoop

    1. Foundation : NSRunLoop
    2. Core Foundation : CFRunLoopRef
  • RunLoopCFRunloopRef都代表着RunLoop对象

    1. NSRunloop是基于CFRunLoopRef的一层OC包装
    2. CFRunLoopRef是开源的
  • Foundation

    1. [NSRunLoop currentRunLoop]; 获得当前线程的 RunLoop对象
    2. [NSRunLoop mainRunLoop]; 获得主线程的RunLoop对象
  • Core Foundation

    1. CFRunLoopRefGetCurrent(); 获得当前线程的 RunLoop对象
    2. CFRunLoopRefGetMain(); 获得主线程的RunLoop对象

注:https://opensource.apple.com/tarballs/CF/

  • 程序并不会马上退出,而是保持运行状态
  • RunLoop的基本作用
    1. 保持程序的持续运行
    2. 处理App中各种事件(如:触摸事件、定时器事件等)
    3. 节省CPU资源,提高程序性能:该做事时做事,该休息时休息
    4. ……


      RunLoop的基本作用1.png

      RunLoop的基本作用2.png

2 . RunLoop与线程

  • 每条线程都有唯一的一个与之对应的RunLoop对象
  • RunLoop保存在一个全局的Dictionary里,线程作为keyRunLoop作为value
  • 线程刚创建时并没有RunLoop对象,RunLoop会在第一次获取它时创建
  • RunLoop会在线程结束时销毁
  • 主线程的RunLoop已经自动获取(创建),子线程默认没有开启RunLoop

3. RunLoop相关的类

  • Core Foundation中关于RunLoop的5个类
    1. CFRunLoopRef
    2. CFRunLoopModeRef
    3. CFRunLoopSourceRef
    4. CFRunLoopTimerRef
    5. CFRunLoopObserverRef
typedef struct __CFRunLoop * CFRunLoopRef;
struct __CFRunLoop {
    pthread_t _pthread;
    CFMutableSetRef _commonModes;
    CFMutableSetRef _commonModeItems;
    CFRunLoopModeRef _currentMode;
    CFMutableSetRef _modes;
};
typedef struct __CFRunLoopMode *CFRunLoopModeRef;
struct __CFRunLoopMode {
    CFStringRef _name;
    CFMutableSetRef _sources0;
    CFMutableSetRef _sources1;
    CFMutableArrayRef _observers;
    CFMutableArrayRef _timers;
};
RunLoop相关的类.png
  • CFRunLoopModeRef

    1. CFRunLoopModeRef代表RunLoop的运行模式
    2. 一个RunLoop包含若干个Mode,每一个Mode又包含若干个sources0/sources1/Timer/observer
    3. RunLoop启动时只能选择其中一个Mode作为currentMode
    4. 如果需要切换Mode,只能退出当前Loop,再重新选择一个Mode进入
      • 不同组的sources0/sources1/Timer/observer能分隔开来,互不影响
    5. 如果Mode里没有sources0/sources1/Timer/observerRunLoop会立马退出
    6. 常见的两种Mode
      • kCFRunLoopDefaultMode(NSDefaultRunLoopMode):App的默认Mode,通常主线程是在这个Mode下运行
      • UITrackingRunLoopMode:界面跟踪Mode,用于ScrollView追踪触摸滑动,保证界面滑动时不受其他Mode影响
  • CFRunLoopObserverRef

/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0), //即将进入Loop
    kCFRunLoopBeforeTimers = (1UL << 1), // 即将处理Timer
    kCFRunLoopBeforeSources = (1UL << 2), // 即将处理Source
    kCFRunLoopBeforeWaiting = (1UL << 5), // 即将进入休眠
    kCFRunLoopAfterWaiting = (1UL << 6), // 刚从休眠中唤醒
    kCFRunLoopExit = (1UL << 7), // 即将退出Loop
    kCFRunLoopAllActivities = 0x0FFFFFFFU
};

二、RunLoop的运行逻辑

  • Source0
    1. 触摸事件处理
    2. performSelector:onThread:
  • Source1
    1. 基于Port的线程间通信
    2. 系统事件捕捉
  • Timers
    1. NSTimer
    2. performSelector:withObject:afterDelay:
  • Observers
    1. 用于监听RunLoop的状态
    2. UI刷新(BeforeWaiting
    3. Autorelease poolBeforeWaiting
RunLoop的运行逻辑.png

三、RunLoop休眠的实现原理

  • 等待消息
    1. 没有消息就让线程休眠
    2. 有消息就唤醒线程


      RunLoop休眠的实现原理.png

四、RunLoop在实际的应用

  • 控制线程生命周期(线程保活)
  • 解决NSTimer在滑动时停止工作的问题
  • 监控应用卡顿
  • 性能优化

注:可能涉及的面试题

  • 讲讲RunLoop,项目中有用到吗
  • RunLoop内部实现逻辑
  • RunLoop和线程的关系
  • timerRunLoop的关系
  • 程序中添加每3秒响应一次的NSTimer,当拖动tableViewtimer可能无法响应要怎么解决
  • RunLoop是怎么响应用户操作的,具体流程是什么样的
  • 说说RunLoop的几种状态
  • RunLoopmode作用是什么

上一篇:
OC底层基础:Block
下一篇:
OC底层基础:多线程GCD

你可能感兴趣的:(OC底层基础:RunLoop)