Runloop

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从源码到应用全面解析

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • RunLoop简介(Introduction) RunLoop是线程基础架构的一部分。RunLoop存在的目的是让...
    吃蘑菇De大灰狼阅读 8,139评论 0 11
  • 摘自《iOS程序员面试笔试真题与解析》 什么时候需要用到runloop机制?一般情况下,一个线程在一段时间内,只能...
    anny_4243阅读 9,152评论 0 5
  • RunLoop的核心,主要是涉及到用户态和内核态的切换(mach_msg())。 基本作用 保持程序运行(main...
    六横六竖亚阅读 3,418评论 0 0
  • 所有的RunLoop保存在一个全局Dictionary里,线程作为key,RunLoop作为value。 RunL...
    Jason1226阅读 2,607评论 0 1
  • 前言 对iOS开发者而言,runloop是一个老生常谈的话题,但凡是iOS开发者,在工作中必然直接或间接的接触过r...
    VV木公子阅读 8,206评论 4 21

友情链接更多精彩内容