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