runloop专题ios 底层

深入浅出 RunLoop(二):数据结构

2019-11-28  本文已影响0人  师大小海腾

RunLoop 系列文章

深入浅出 RunLoop(一):初识
深入浅出 RunLoop(二):数据结构
深入浅出 RunLoop(三):事件循环机制
深入浅出 RunLoop(四):RunLoop 与线程
深入浅出 RunLoop(五):RunLoop 与 NSTimer
iOS - 聊聊 autorelease 和 @autoreleasepool:RunLoop 与 @autoreleasepool

网络配图.jpg

目录

  • CFRunLoopRef
  • CFRunLoopModeRef
    RunLoop 的常见模式
    CFRunLoopModeRef 这样设计有什么好处?Runloop为什么会有多个 Mode?
  • CFRunLoopSourceRef
  • CFRunLoopTimerRef
  • CFRunLoopObserverRef

CFRunLoopRef

RunLoop对象的底层就是一个CFRunLoopRef结构体,它里面存储着:

// CFRunLoop.h
typedef struct __CFRunLoop * CFRunLoopRef;
// CFRunLoop.c
struct __CFRunLoop {
    pthread_t _pthread;  // 与线程一一对应
    CFMutableSetRef _commonModes;
    CFMutableSetRef _commonModeItems;
    CFRunLoopModeRef _currentMode;
    CFMutableSetRef _modes;
    ...
};

CFRunLoopModeRef

// CFRunLoop.h
typedef struct __CFRunLoopMode *CFRunLoopModeRef;
// CFRunLoop.c
struct __CFRunLoopMode {
    CFStringRef _name;             // mode 类型,如:NSDefaultRunLoopMode
    CFMutableSetRef _sources0;     // CFRunLoopSourceRef
    CFMutableSetRef _sources1;     // CFRunLoopSourceRef
    CFMutableArrayRef _observers;  // CFRunLoopObserverRef
    CFMutableArrayRef _timers;     // CFRunLoopTimerRef
    ...
};

RunLoop 的常见模式

ModeName 描述
NSDefaultRunLoopMode / KCFRunLoopDefaultMode 默认模式
UITrackingRunLoopMode 界面追踪模式,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响;
NSRunLoopCommonModes / KCFRunLoopCommonModes 通用模式(默认包含 KCFRunLoopDefaultMode 和 UITrackingRunLoopMode)

该模式不是实际存在的一种模式,它只是一个特殊的标记,是同步Source0/Source1/Timer/Observer到多个 Mode 中的技术方案。被标记为通用模式的Source0/Source1/Timer/Observer都会存放到 _commonModeItems 集合中,会同步这些Source0/Source1/Timer/Observer到多个 Mode 中。

备注:

  • NSDefaultRunLoopModeNSRunLoopCommonModes属于Foundation框架;
  • KCFRunLoopDefaultModeKCFRunLoopCommonModes属于Core Foundation框架;
  • 前者是对后者的封装,作用相同。

CFRunLoopModeRef 这样设计有什么好处?Runloop为什么会有多个 Mode?

CFRunLoopSourceRef

// CFRunLoop.h
typedef struct __CFRunLoopSource * CFRunLoopSourceRef;
// CFRunLoop.m
struct __CFRunLoopSource {
    CFRuntimeBase _base;
    uint32_t _bits;
    pthread_mutex_t _lock;
    CFIndex _order;                         /* immutable */
    CFMutableBagRef _runLoops;
    union {
        CFRunLoopSourceContext version0;    /* immutable, except invalidation */
        CFRunLoopSourceContext1 version1;   /* immutable, except invalidation */
    } _context;
};

Source0 和 Source1 的区别:

Input Sources 区别
Source0 需要手动唤醒线程:添加Source0RunLoop并不会主动唤醒线程,需要手动唤醒)
① 触摸事件处理
performSelector:onThread:
Source1 具备唤醒线程的能力
① 基于 Port 的线程间通信
② 系统事件捕捉:系统事件捕捉是由Source1来处理,然后再交给Source0处理

CFRunLoopTimerRef

// CFRunLoop.h
typedef struct CF_BRIDGED_MUTABLE_TYPE(NSTimer) __CFRunLoopTimer * CFRunLoopTimerRef;
// CFRunLoop.c
struct __CFRunLoopTimer {
    CFRuntimeBase _base;
    uint16_t _bits;
    pthread_mutex_t _lock;
    CFRunLoopRef _runLoop;           // 添加该 timer 的 RunLoop
    CFMutableSetRef _rlModes;        // 所有包含该 timer 的 modeName
    CFAbsoluteTime _nextFireDate;
    CFTimeInterval _interval;        /* immutable 理想时间间隔 */    
    CFTimeInterval _tolerance;       /* mutable 时间偏差 */  
    uint64_t _fireTSR;               /* TSR units */
    CFIndex _order;                  /* immutable */
    CFRunLoopTimerCallBack _callout; /* immutable 回调入口 */
    CFRunLoopTimerContext _context;  /* immutable, except invalidation */
};

CFRunLoopObserverRef

作用

/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0),          // 即将进入 RunLoop
    kCFRunLoopBeforeTimers = (1UL << 1),   // 即将处理 Timers
    kCFRunLoopBeforeSources = (1UL << 2),  // 即将处理 Sources
    kCFRunLoopBeforeWaiting = (1UL << 5),  // 即将进入休眠
    kCFRunLoopAfterWaiting = (1UL << 6),   // 刚从休眠中唤醒
    kCFRunLoopExit = (1UL << 7),           // 即将退出 RunLoop
    kCFRunLoopAllActivities = 0x0FFFFFFFU  // 表示以上所有状态
};

定义

// CFRunLoop.h
typedef struct __CFRunLoopObserver * CFRunLoopObserverRef;
// CFRunLoop.c
struct __CFRunLoopObserver {
    CFRuntimeBase _base;
    pthread_mutex_t _lock;
    CFRunLoopRef _runLoop;              // 添加该 observer 的 RunLoop
    CFIndex _rlCount;
    CFOptionFlags _activities;          /* immutable 监听的活动状态 */
    CFIndex _order;                     /* immutable */
    CFRunLoopObserverCallBack _callout; /* immutable 回调入口 */
    CFRunLoopObserverContext _context;  /* immutable, except invalidation */
};

CFRunLoopObserverRef中的_activities用来保存RunLoop的活动状态。当RunLoop的状态发生改变时,通过回调_callout通知所有监听这个状态的Observer

下一篇

深入浅出 RunLoop(三):事件循环机制

上一篇下一篇

猜你喜欢

热点阅读