美文网首页
Runloop 学习

Runloop 学习

作者: Tony17 | 来源:发表于2020-02-28 07:59 被阅读0次

前言

在提到OC的时候,我们不可避免的会提到 Runloop 和 Runtime。但是Runloop到底是怎么工作的,我之前一直没有研究过,今天开看一下。

Runloop简单介绍

RunLoop就是事件循环,在程序运行过程中循环做一些事情。

基本作用

  • 保持程序持续运行
  • 处理App中的各种事件(触摸事件、定时器事件等)
  • 节省CPU资源,提高程序性能: 该做事时候做事,该休息时休息(普通while循环是忙等待,RunLoop是闲等待)

应用范畴

  • 定时器(Timer)、PerformSelector
  • GCD Async Main Queue
  • 时间响应、手势识别、界面刷新
  • 网络请求
  • AutoreleasePool

RunLoop与线程的关系

  • 每条线程都有唯一的一个与之对应的RunLoop对象
  • RunLoop保存在一个全局的Dictionary里,线程作为keyRunLoop作为value
  • 线程刚创建时并没有RunLoop对象,RunLoop会在第一次获取它时创建
  • RunLoop会在线程结束时销毁
  • 主线程的RunLoop已经自动获取(创建),子线程默认没有开启RunLoop
自动释放池

自动释放池的底层数据结构主要是 __AtAutoreleasePool、AutoreleasePollPage。调用了 autorelease 的对象最终都是通过 AutoreleasePollPage 对象管理的。

AutoReleasePoolPage的结构如下:


AutoReleasePoolPage_struct.png
  • 每个 AutoreleasePoolPage 对象占用 4096 字节内存,除了用来存放它内部的成员变量,剩下的空间用来存放 autorelease 对象的地址
  • 所有的 AutoreleasePoolPage 对象通过双向链表的形式连接在一起
  • 调用push方法会将一个 POOL_BOUNDARY 入栈,并且返回其存放的内存地址
  • 调用 pop 方法时传入一个 POOL_BOUNDARY 的内存地址,会从最后一个入栈的对象开始发送 release 消息,直到遇到这个 POOL_BOUNDARY
  • id *next指向了下一个能存放 autorelease 对象地址的区域

RunLoop 和 AutoreleasePool 的关系

主线程中的RunLoop注册了2个Observer

  1. 第一个 Observer 监听了 kCFRunLoopEntry 事件,会调用 objc_autoreleasePoolPush()
  2. 第二个 Observer 监听了2个事件
    1. 监听了 kCFRunLoopBeforeWaiting 事件,会调用 objc_autoreleasePoolPop()、objc_autoreleasePoolPush()
    2. 监听了 kCFRunLoopBeforeExit 事件,会调用 objc_autoreleasePoolPop()

获取RunLoop对象:

  • Foundation
    • [NSRunLoop currentRunLoop]; // 获得当前线程的RunLoop对象
    • [NSRunLoop mainRunLoop]; // 获得主线程的RunLoop对象
  • Core Foundation
    • CFRunLoopGetCurrent(); // 获得当前线程的RunLoop对象
    • CFRunLoopGetMain(); // 获得主线程的RunLoop对象

CoreFoundation中关于RunLoop有5个类:

  • CFRunLoopRef
  • CFRunLoopModeRef
  • CFRunLoopSourceRef
  • CFRunLoopTimerRef
  • CFRunLoopObserverRef

RunLoopMode

RunLoopModeRunLoop的运行模式,RunLoop总是在各种Mode之间切换

  • CFRunLoopModeRef代表RunLoop的运行模式
    • UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个Mode,启动完成后就不再使用。
    • GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到。
    • kCFRunLoopDefaultMode(NSDefaultRunLoopMode): App默认的Mode,通常主线程是在这个Mode下运行
    • UITrackingRunLoopMode: 界面跟踪Mode,用于ScrollView追踪触摸滑动,保证界面滑动时不受其他Mode的影响
    • kCFRunLoopCommonModes (NSRunLoopCommonModes): 这是一个占位的Mode, 无论当前是哪种Mode,都可以执行这个该Mode下的事件
  • 一个RunLoop包含若干个Mode,每个Mode又包含若干个Source0/Source1/Timer/Observer
  • RunLoop启动时只能选择其中一个Mode,作为currentMode
  • 如果需要切换Mode,只能退出当前Loop,再重新选择一个Mode进入
  • 不同组的Source0/Source1/Timer/Observer能分隔开来,互不影响
  • 如果Mode里没有任何Source0/Source1/Timer/ObserverRunLoop会立马退出

RunLoop 执行流程

先上图,网上找的RunLoop执行流程:

runloop-introduce.png

运行逻辑:

信号源解释:

  • Source0
    • 触摸事件处理
    • performSelector:onThread:
  • Source1
    • 基于Port的线程间通信
    • 系统事件捕捉,触摸屏幕的事件是先触发Source1,然后再由Source1包装成Source0
  • Timers
    • NSTimer
    • performSelector:withObject:afterDelay:
  • Observers
    • 用于监听RunLoop的状态
    • UI刷新(BeforeWaiting),当代码设置UI变动时,并不会立即处理,而是会等到RunLoop即将进入睡眠状态的时候,统一刷新UI
    • Autorelease poolBeforeWaiting),pool中的数据并不会立即释放,而是在RunLoop即将睡眠的时候才会释放pool中的数据
runloop.png

RunLoop状态

type explain
KCFRunLoopEntry 即将进入Loop
KCFRunLoopBeforeTimers 即将处理Timer
KCFRunLoopBeforeSources 即将处理Source
KCFRunLoopBeforeWaiting 即将进入休眠
KCFRunLoopAfterWaiting 刚从休眠中唤醒
KCFRunLoopExit 即将退出Loop
KCFRunLoopAllActivities 所有状态改变 - 监听时用来监听所有状态

线程休眠原理:

  • 当需要休眠时,线程从用户态切换到内核态(mach_msg())
  • 当需要处理消息时候,线程从内核态切换到用户态并处理消息(mach_msg())

NSTimer “不准时” 问题

问题: NSTimer依赖于 NSRunLoop,如果 RunLoop的任务过于繁重,可能会导致 NSTimer 不准时
解决办法: 使用GCD定时器

gcd_timer.png

实际开发中的运用

  • 控制线程生命周期(线程保活)
  • 解决NSTimer在滑动时停止工作的问题
  • 监控应用卡顿
  • 性能优化

最后

以上就是我学习的全部内容,势必会有遗漏或错误的地方,欢迎斧正~

相关文章

  • IOS runloop 学习笔记

    这次学习 的内容是 runloop 1.runloop 是什么2.runloop 的作用3.runloop 和 线...

  • RunLoop学习资料

    非常好的runloop学习系列 CoreFoundation源码 RunLoop系列之源码分析 关于Runloop...

  • NSRunLoop

    前言 RunLoop的初期学习总结,后续会持续研究更新。 一、Runloop定义及作用 1. 什么是Runloop...

  • RunLoop学习总结

    通过以下文章学习记录 关于Runloop的原理探究及基本使用 深入理解RunLoop RunLoop完全指南 Ru...

  • RunLoop-基础概念(初识篇)

    学习这篇内容主要讲解RunLoop的概念,以及RunLoop和线程之间的关系。当然提及RunLoop也离不开Aut...

  • Runloop学习

    Runloop学习 | 目录 ||: ------------- || 1 什么是...

  • RunLoop学习

    RunLoop概念 人如其名,RunLoooooooooooooooop,像是一个死循环,不停的跑圈,永不懈怠。除...

  • Runloop学习

    深入理解RunLoop | Garan no dou

  • RunLoop学习

    读这篇Blog:https://blog.ibireme.com/2015/05/18/runloop/ 收货比较...

  • Runloop学习

    苹果官方的简介: The programmatic interface to objects that manag...

网友评论

      本文标题:Runloop 学习

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