ios⋯⋯runloop runtimeiOS Runloop

runloop学习记录

2018-04-07  本文已影响12人  Corbin___

1.runloop源码

源码

Snip20180407_10.png

2.对象介绍

image.png

接下来的对象介绍,可以借助这个图理清对象间的关系

// 一个runloop对象
typedef struct __CFRunLoop * CFRunLoopRef;
// source
typedef struct __CFRunLoopSource * CFRunLoopSourceRef;
// observer观察者
typedef struct __CFRunLoopObserver * CFRunLoopObserverRef;
// timer
typedef struct __CFRunLoopTimer * CFRunLoopTimerRef;
// mode
typedef struct __CFRunLoopMode *CFRunLoopModeRef;

2.1. CFRunLoopRef

一个指向__CFRunLoop结构体的指针

struct __CFRunLoop {
    CFRuntimeBase _base;
    pthread_mutex_t _lock;          /* locked for accessing mode list */
    __CFPort _wakeUpPort;           // used for CFRunLoopWakeUp 
    Boolean _unused;
    volatile _per_run_data *_perRunData;              // reset for runs of the run loop
    pthread_t _pthread;
    uint32_t _winthread;
    CFMutableSetRef _commonModes;
    CFMutableSetRef _commonModeItems;
    CFRunLoopModeRef _currentMode;
    CFMutableSetRef _modes;
    struct _block_item *_blocks_head;
    struct _block_item *_blocks_tail;
    CFTypeRef _counterpart;
};

从这个结构体的内容可以看出:

2.2. CFRunLoopSourceRef

一个指向__CFRunLoopSource结构体的指针

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;
};
typedef struct {
    CFIndex version;
    void *  info;
    const void *(*retain)(const void *info);
    void    (*release)(const void *info);
    CFStringRef (*copyDescription)(const void *info);
    Boolean (*equal)(const void *info1, const void *info2);
    CFHashCode  (*hash)(const void *info);
    void    (*schedule)(void *info, CFRunLoopRef rl, CFStringRef mode);
    void    (*cancel)(void *info, CFRunLoopRef rl, CFStringRef mode);
    void    (*perform)(void *info);
} CFRunLoopSourceContext;

typedef struct {
    CFIndex version;
    void *  info;
    const void *(*retain)(const void *info);
    void    (*release)(const void *info);
    CFStringRef (*copyDescription)(const void *info);
    Boolean (*equal)(const void *info1, const void *info2);
    CFHashCode  (*hash)(const void *info);
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) || (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)
    mach_port_t (*getPort)(void *info);
    void *  (*perform)(void *msg, CFIndex size, CFAllocatorRef allocator, void *info);
#else
    void *  (*getPort)(void *info);
    void    (*perform)(void *info);
#endif
} CFRunLoopSourceContext1;
version0 / source0 source0 是非基于 port 的事件,主要是 APP 内部事件,如点击事件,触摸事件等
version1 / source1 source1 是基于Port的,通过内核和其他线程通信,接收,分发系统事件。

2.3. CFRunLoopObserverRef

一个指向__CFRunLoopObserver结构体的指针
作用:观察者,观察runloop的各种状态,并通过回调抛出去

struct __CFRunLoopObserver {
    CFRuntimeBase _base;
    pthread_mutex_t _lock;
    CFRunLoopRef _runLoop;
    CFIndex _rlCount;
    CFOptionFlags _activities;      /* immutable */
    CFIndex _order;         /* immutable */
    CFRunLoopObserverCallBack _callout; /* immutable */
    CFRunLoopObserverContext _context;  /* immutable, except invalidation */
};

其中的CFOptionFlags是一个枚举:表示runloop的状态

/* 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    // 占位
};


CFRunLoopObserverRef观察者会将观察到的状态变化通过回调_callout跑出去
看下这个CFRunLoopObserverCallBack _callout

// 这个回调可以将观察者、runloop状态、info传出去
typedef void (*CFRunLoopObserverCallBack)(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info);

2.4. CFRunLoopTimerRef

是一个指向__CFRunLoopTimer结构体的指针

某些数据类型能够在Core Foundation和Foundation之间互换使用,可被互换使用的数据类型被称为Toll-Free Bridged类型。

struct __CFRunLoopTimer {
    CFRuntimeBase _base;
    uint16_t _bits;
    pthread_mutex_t _lock;
    CFRunLoopRef _runLoop;
    CFMutableSetRef _rlModes;
    CFAbsoluteTime _nextFireDate;
    CFTimeInterval _interval;       /* immutable */
    CFTimeInterval _tolerance;          /* mutable */
    uint64_t _fireTSR;          /* TSR units */
    CFIndex _order;         /* immutable */
    CFRunLoopTimerCallBack _callout;    /* immutable */
    CFRunLoopTimerContext _context; /* immutable, except invalidation */
};

2.5.CFRunLoopModeRef

一个指向__CFRunLoopMode结构体的指针

typedef struct __CFRunLoopMode *CFRunLoopModeRef;

struct __CFRunLoopMode {
    CFRuntimeBase _base;
    pthread_mutex_t _lock;  /* must have the run loop locked before locking this */
    CFStringRef _name;
    Boolean _stopped;
    char _padding[3];
    CFMutableSetRef _sources0;
    CFMutableSetRef _sources1;
    CFMutableArrayRef _observers;
    CFMutableArrayRef _timers;
    CFMutableDictionaryRef _portToV1SourceMap;
    __CFPortSet _portSet;
    CFIndex _observerMask;
#if USE_DISPATCH_SOURCE_FOR_TIMERS
    dispatch_source_t _timerSource;
    dispatch_queue_t _queue;
    Boolean _timerFired; // set to true by the source when a timer has fired
    Boolean _dispatchTimerArmed;
#endif
#if USE_MK_TIMER_TOO
    mach_port_t _timerPort;
    Boolean _mkTimerArmed;
#endif
#if DEPLOYMENT_TARGET_WINDOWS
    DWORD _msgQMask;
    void (*_msgPump)(void);
#endif
    uint64_t _timerSoftDeadline; /* TSR */
    uint64_t _timerHardDeadline; /* TSR */
};


3.函数介绍

3.1.__CFRunLoopDoObservers

通知Observer,runloop要做什么事情
这个__CFRunLoopDoObservers函数需要传三个参数,分别是

3.2._CFRunLoopGet0

runloop对象是存在全局字典中的,key就是pthread_t
这个_CFRunLoopGet0函数的作用就是获取对应线程的runloop

实现思路(依据就是下面截图的源码)
1.先判断这个全局字典存不存在,不存在,创建一个,并将主线程的runloop加进去
2.直接去字典里取这个loop
3.如果loop不存在,就创建一个loop加入到全局字典中
// 伪代码
if(!__CFRunLoops) {
      1.创建全局字典
      2.创建主线程loop,并加入到全局字典中
}
根据线程pthread_t为key,去字典取对应的loop
if(!loop) {
      1.创建loop
      2.加入到字典中
}
return loop

其实这个说明了runloop和线程是一一对应的关系

Snip20180407_22.png

3.3.获取主线程loop和获取当前的loop

image.png

参考文档

强力推荐
RunLoop系列之要点提炼
RunLoop系列之源码分析
iOS刨根问底-深入理解RunLoop
深入理解 RunLoop

上一篇 下一篇

猜你喜欢

热点阅读