iOS底层原理探索 之 RunLoop 详解

412 阅读4分钟
写在前面: iOS底层原理探究是本人在平时的开发和学习中不断积累的一段进阶之
路的。 记录我的不断探索之旅,希望能有帮助到各位读者朋友。

目录如下:

  1. iOS 底层原理探索 之 alloc
  2. iOS 底层原理探索 之 结构体内存对齐
  3. iOS 底层原理探索 之 对象的本质 & isa的底层实现
  4. iOS 底层原理探索 之 isa - 类的底层原理结构(上)
  5. iOS 底层原理探索 之 isa - 类的底层原理结构(中)
  6. iOS 底层原理探索 之 isa - 类的底层原理结构(下)
  7. iOS 底层原理探索 之 Runtime运行时&方法的本质
  8. iOS 底层原理探索 之 objc_msgSend
  9. iOS 底层原理探索 之 Runtime运行时慢速查找流程
  10. iOS 底层原理探索 之 动态方法决议
  11. iOS 底层原理探索 之 消息转发流程
  12. iOS 底层原理探索 之 应用程序加载原理dyld (上)
  13. iOS 底层原理探索 之 应用程序加载原理dyld (下)
  14. iOS 底层原理探索 之 类的加载
  15. iOS 底层原理探索 之 分类的加载
  16. iOS 底层原理探索 之 关联对象
  17. iOS底层原理探索 之 魔法师KVC
  18. iOS底层原理探索 之 KVO原理|8月更文挑战
  19. iOS底层原理探索 之 重写KVO|8月更文挑战
  20. iOS底层原理探索 之 多线程原理|8月更文挑战
  21. iOS底层原理探索 之 GCD函数和队列
  22. iOS底层原理探索 之 GCD原理(上)
  23. iOS底层 - 关于死锁,你了解多少?
  24. iOS底层 - 单例 销毁 可否 ?
  25. iOS底层 - Dispatch Source
  26. iOS底层 - 一个栅栏函 拦住了 数
  27. iOS底层 - 不见不散 的 信号量
  28. iOS底层 GCD - 一进一出 便成 调度组
  29. iOS底层原理探索 - 锁的基本使用
  30. iOS底层 - @synchronized 流程分析
  31. iOS底层 - 锁的原理探索
  32. iOS底层 - 带你实现一个读写锁
  33. iOS底层 - 谈Objective-C block的实现(上)
  34. iOS底层 - 谈Objective-C block的实现(下)
  35. iOS底层 - Block, 全面解析!
  36. iOS底层 - 启动优化(上)
  37. iOS底层 - 启动优化(下)
  38. iOS底层原理探索 -- 内存管理 之 内存五大区
  39. iOS底层原理探索 -- 内存管理 之 Tagged Pointer Format Changes
  40. iOS底层原理探索 -- 内存管理 之 retain & release
  41. iOS底层原理探索 -- 内存管理 之 弱引用表
  42. iOS底层原理探索 -- 内存管理 之 @autoreleasepool
  43. iOS底层原理探索 之 RunLoop 概念

以上内容的总结专栏


细枝末节整理


前言

上一篇我们主要讲解了runloop的相关概念介绍,今天,我们从底层的角度,开始深入剖析 RunLoop 的结构和实现原理。

RunLoop 的作用

  • Runloop 可以保持我们的程序持续的运行;
  • 处理App中的各种事件(触摸,定时器,performSelect);
  • 节省CPU资源:该工作就工作,该休息就休息。

RunLoop 的数据结构

通过下符号断点,我们可以定位到 RunLoop 源码在 CoreFoundation 中。

image.png

打开 CoreFoundation 的源码 :

底层是 do {} while () 循环实现

void CFRunLoopRun(void) {    /* DOES CALLOUT */
    int32_t result;
    do {
        result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false);
        CHECK_FOR_FORK();
    } while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result);
}
CFRunLoopRef CFRunLoopGetCurrent(void) {
    CHECK_FOR_FORK();
    CFRunLoopRef rl = (CFRunLoopRef)_CFGetTSD(__CFTSDKeyRunLoop);
    if (rl) return rl;
    return _CFRunLoopGet0(pthread_self());
}

线程和runloop是一一对应的关系

CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) {

    if (pthread_equal(t, kNilPthreadT)) {
        //主线程
        t = pthread_main_thread_np();
    }
    
    __CFLock(&loopsLock);
    if (!__CFRunLoops) {
        __CFUnlock(&loopsLock);
        
    CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
        
        
    CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np());
        
    // 进行绑定 dict[@"pthread_main_thread_np"] = mainLoop
    CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop);
            
    ...
    
    if (!loop) {
    //    通过线程 创建 runloop
    CFRunLoopRef newLoop = __CFRunLoopCreate(t);
        __CFLock(&loopsLock);
        
    loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
    
    if (!loop) {
    
        //没有获取到就存储线程和runloop
        CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);
        loop = newLoop;
    }
   
   ...
   
    return loop;
}

__CFRunLoop

runloop 包含多个 mode 和 item ;包含线程信息;

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;
    CFAbsoluteTime _runTime;
    CFAbsoluteTime _sleepTime;
    CFTypeRef _counterpart;
};

系统默认注册了 5 个 Mode:

  1. kCFRunLoopDefaultMode : App 的默认 Mode,通常主线程是在这个 Mode 下面运行的
  2. UITrackingRunLoopMode : 界面跟踪 Mode,用于 ScrollView 追踪触摸滑动
  3. UIInitializationRunLoopMode : 在刚启动 App 时进入的第一个 Mode,启动完后就不再使用
  4. GSEventReceiveRunLoopMode : 接受系统事件的内部 Mode,通常用不到
  5. kCFRunLoopCommonModes : 这是一个占位的 Mode,没有实际作用

__CFRunLoopMode

mode 包含多个_sources0、_sources1、_observers和_timers

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

也就是 items (_sources0、_sources1、_observers和_timers) 依赖于 mode 在runloop 中执行。

今天看到一片很好的runloop文章,在这里分享给大家: www.cocoachina.com/articles/11…