Runloop

作者: e521 | 来源:发表于2023-01-29 15:32 被阅读0次

    1、什么是Runloop?

    • 运行循环,俗称为跑圈,内部就是一个do-while循环,用于处理应用的各种事件,保证程序的正常运行。

    2、Runloop能做些什么?

    • 处理crash问题
    • 线程保活
    • 检测、优化卡顿问题

    3、线程和Runloop有什么关系?

    • 线程和Runloop是一一对应的,且以key和value的形式进行存储的。
        if (!__CFRunLoops) {
            __CFUnlock(&loopsLock);
          // 创建字典
        CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
          // 创建主线程
        CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np());
          // 建立主线程和runloop之间的联系
        CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop);
        if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&__CFRunLoops)) {
            CFRelease(dict);
        }
    

    4.Runloop的构成

    • Runloop是由多个mode组成 mode又由sources0,sources1,observers ,timers构成
    • sources0是非基于port的任务事件,需要手动唤醒线程
    • sources1 用于处理内核事件,即port相关的,能主动唤醒runloop

    5.如何启动runloop

    启动runlopp的三种方式:

    - (void)run NS_SWIFT_UNAVAILABLE_FROM_ASYNC("run cannot be used from async contexts.");
    
    - (void)runUntilDate:(NSDate *)limitDate NS_SWIFT_UNAVAILABLE_FROM_ASYNC("run(until:) cannot be used from async contexts.");
    
    - (BOOL)runMode:(NSRunLoopMode)mode beforeDate:(NSDate *)limitDate
    

    前两种方式是基于while循环的调用第三种启动方式,前两种方式是一种无限循环。

        public func run() {
            while run(mode: .default, before: Date.distantFuture) { }
        }
    
        public func run(until limitDate: Date) {
            while run(mode: .default, before: limitDate) && limitDate.timeIntervalSinceReferenceDate > CFAbsoluteTimeGetCurrent() { }
        }
    
        public func run(mode: RunLoop.Mode, before limitDate: Date) -> Bool {
            if _cfRunLoop !== CFRunLoopGetCurrent() {
                return false
            }
            let modeArg = mode._cfStringUniquingKnown
            if _CFRunLoopFinished(_cfRunLoop, modeArg) {
                return false
            }
            
            let limitTime = limitDate.timeIntervalSinceReferenceDate
            let ti = limitTime - CFAbsoluteTimeGetCurrent()
            CFRunLoopRunInMode(modeArg, ti, true)
            return true
        }
    

    6、Runloop有几种状态

    • kCFRunLoopEntry:进入loop,在调用__CFRunLoopRun函数前,会被标记为这个状态。
    • kCFRunLoopBeforeTimers:触发 Timer 回调,判断是有Timer触发的话会走Timer回调,走回调前会被标记为这个状态。
    • kCFRunLoopBeforeSources:触发 Source0 回调,判断是Source0触发的话会走Source0回调,走回调前会被标记为这个状态。
    • kCFRunLoopBeforeWaiting:将要进入休眠。等待 mach_port 消息,在处理完事件后,会标记为这个状态,然后进入到内部的do while循环中等待激活。
    • kCFRunLoopAfterWaiting:从休眠中唤醒。 接收 mach_port 消息,已经被激活,在处理事件前会标记为这个状态。然后开始处理事件。
    • kCFRunLoopExit:退出 loop

    7、主线程需要保活吗?保活的方式有几种?

    • 主线程不需要保活,子线程的保活方式有两种方式,一种是通过runloop,一种是通过NSCondition方式进行保活,runloop的方式可以细分为通过timer和port的方式保活

    参考链接:
    iOS 线程保活
    Runloop
    RunLoop从源码到应用全面解析

    相关文章

      网友评论

          本文标题:Runloop

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