美文网首页
iOS界面卡顿监测

iOS界面卡顿监测

作者: 面试小集 | 来源:发表于2017-10-08 13:38 被阅读143次

    RunLoop

    1. RunLoop是与线程相关的概念。
    2. 在Cocoa和Core Foundation框架中提供了runloop对象以便帮助你配置和管理线程的runloop。
    3. 每一个线程都有与之相关的runloop对象,只有非主线程需要显示的去启动它的runloop,主线程的runloop随着应用程序的开启的已经被设置和启动了。
    4. 线程和RunLoop之间是一一对应的。其关系保存在一个全局的Dictionary中,线程刚创建时并没有RunLoop,如果你不主动获取,它一直不会有,RunLoop的创建发生在第一次获取时。
    5. CFRunLoopGetCurrent()获取当前线程的RunLoop对象,** CFRunLoopGetMain()**获取主线程的runloop对象。

    RunLoop Model

    model item

    input source:
    intput source有两种:source0 表示:Custom Source, source1表示:Port-Based Source
    Source0 只包含了一个回调(函数指针),它并不能主动触发事件。使用时,你需要先调用 CFRunLoopSourceSignal(source),将这个 Source 标记为待处理,然后手动调用 CFRunLoopWakeUp(runloop) 来唤醒 RunLoop,让其处理这个事件。
    Source1 包含了一个 mach_port 和一个回调(函数指针),被用于通过内核和其他线程相互发送消息。这种 Source 能主动唤醒 RunLoop 的线程。
    Timer source:
    在预设的时间点同步的传递消息。Timer是线程通知自己做某件事的一种方式。
    它和 NSTimer 是toll-free bridged 的,可以混用。其包含一个时间长度和一个回调(函数指针)。当其加入到 RunLoop 时,RunLoop会注册对应的时间点,当时间点到时,RunLoop会被唤醒以执行那个回调。
    Observer:
    每个 Observer 都包含了一个回调(函数指针),当 RunLoop 的状态发生变化时,观察者就能通过回调接受到这个变化。可以观测的时间点有以下几个:

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

    Model comment属性

    苹果公开提供的 Mode 有两个:kCFRunLoopDefaultMode (NSDefaultRunLoopMode) 和 UITrackingRunLoopMode,你可以用这两个 Mode Name 来操作其对应的 Mode。

    CFRunLoopMode 和 CFRunLoop 的结构大致如下:

    struct __CFRunLoopMode {
        CFStringRef _name;            // Mode Name, 例如 @"kCFRunLoopDefaultMode"
        CFMutableSetRef _sources0;    // Set
        CFMutableSetRef _sources1;    // Set
        CFMutableArrayRef _observers; // Array
        CFMutableArrayRef _timers;    // Array
        ...
    };
    
    struct __CFRunLoop {
        CFMutableSetRef _commonModes;     // Set
        CFMutableSetRef _commonModeItems; // Set<Source/Observer/Timer>
        CFRunLoopModeRef _currentMode;    // Current Runloop Mode
        CFMutableSetRef _modes;           // Set
        ...
    }
    

    这里有个概念叫 “CommonModes”:一个 Mode 可以将自己标记为”Common”属性(通过将其 ModeName 添加到 RunLoop 的 “commonModes” 中)。每当 RunLoop 的内容发生变化时,RunLoop 都会自动将 _commonModeItems 里的 Source/Observer/Timer 同步到具有 “Common” 标记的所有Mode里。

    应用场景举例:主线程的 RunLoop 里有两个预置的 Mode:kCFRunLoopDefaultMode 和 UITrackingRunLoopMode。这两个 Mode 都已经被标记为”Common”属性。(在_commonModes里面)。
    DefaultMode 是 App 平时所处的状态,TrackingRunLoopMode 是追踪 ScrollView 滑动时的状态。当你创建一个 Timer 并加到 DefaultMode 时,Timer 会得到重复回调,但此时滑动一个TableView时,RunLoop 会将 mode 切换为 TrackingRunLoopMode,这时 Timer 就不会被回调,并且也不会影响到滑动操作。

    有时你需要一个 Timer,在两个 Mode 中都能得到回调,一种办法就是将这个 Timer 分别加入这两个 Mode。还有一种方式,就是将 Timer 加入到顶层的 RunLoop 的 “commonModeItems” 中。”commonModeItems” 被 RunLoop 自动更新到所有具有”Common”属性的 Mode 里去。

    runloop执行过程

    图片来自阿里百川
    图片来自阿里百川图片来自阿里百川

    参考资料

    iOS实时卡顿监控
    深入理解RunLoop
    移动端监控体系之技术原理剖析
    关于RunLoop部分源码的注释
    什么是 Event Loop
    阿里百川码力APP监控来了 重量级选手进入APM市场
    apple开发文档-runloop
    Run Loop学习笔记和摘抄

    相关文章

      网友评论

          本文标题:iOS界面卡顿监测

          本文链接:https://www.haomeiwen.com/subject/ruveyxtx.html