前言

为了增强自己对于RunLoop的理解,故写下该文章来加深自己的印象和理解,以下内容中如果有错误或不准确的地方,欢迎指正。唯有相互学习,才能成长。

什么是RunLoop

RunLoop通常翻译为运行循环,所以顾名思义是指程序要运行过程中循环的去做一些事情。其实在iOS开发中我们很多地方都有用到RunLoop,其中包括:GCD,手势事件处理,Timer定时器,界面刷新等等都和RunLoop息息相关。

RunLoop的底层实现的话相当于do-while循环,当我们创建iOS程序时其实在main.m中就有了这样一种结构,所以这样iOS程序才不会立马就退出,而是一直保持运行状态。

ios runloop停止 ios runloop应用_objective-c


RunLoop在程序中的作用:1、保持程序的持续运行;2、处理事件(定时器,手势等);3、节省CPU资源,在没有事情的时候就休眠等等

RunLoop与线程的关系

RunLoop与线程的关系是一一对应的,即每条线程对应一个RunLoop对象,线程刚刚创建时没有RunLoop对象,RunLoop会在第一次获取时创建;主线程的RunLoop自动创建,子线程没有开启RunLoop;RunLoop会在线程生命周期结束时销毁;RunLoop在内存中存储在以线程作为key,RunLoop为value的全局hash表中。

RunLoop的底层结构

针对于RunLoop相关的操作,iOS提供了两套API,Foundation中的NSRunLoopCoreFoundation中的CFRunLoopRefNSRunLoopCFRunLoopRef都代表着RunLoop对象,前者是基于后者的封装,而后者是开源的,感兴趣可见Core Foundation开源

ios runloop停止 ios runloop应用_iOS_02


从底层来看RunLoop中存储这对应的线程_pthread以及mode相关集合。而且CFRunLoopModeRef结构则如下图所示:

ios runloop停止 ios runloop应用_iOS_03


所以可以知道RunLoop对象中会存在多个Mode而每个Mide都会包含多个source0,source1,observers及timers。Mode指的是RunLoop运行模式,

如果切换Mode则只能退出当前Loop再重新选择Mode进入。当Mode中没有任何的source0,source1,observers及timers时,RunLoop会立马退出。

日常开发中常用的两种Mode:

NSDefaultRunLoopMode:App默认Mode,通常主线程运行在该Mode下;

UITrackingRunLoopMode:界面跟踪Mode,用于UIScrollView追踪触摸滑动,保证界面滑动时不受其他Mode影响。

Source0:触摸事件处理,performSelector:onThread:

Source1:用于Port线程间通信,系统时间的捕捉

Times:NSTimer,performSelector:withObject:afterDelay:

Observers:监听RunLoop状态,UI刷新,自动释放池

RunLoop运行逻辑

  1. 通知Observers:进入Loop
  2. 通知Observers:即将处理Timers
  3. 通知Observers:即将处理Sources
  4. 处理Blocks
  5. 处理Source0(可能会再次处理Block)
  6. 如果存在Source1,跳转至第8步
  7. 通知Observers:开始休眠(等待消息唤醒)
  8. 通知Observers:结束休眠(被某个消息唤醒)
    1>处理Timer
    2>处理GCD,Async To Main Queue
    3>处理Source1
  9. 处理Blocks
  10. 根据前面执行结果决定如何操作
    1>回到2步
    2>退出Loop
  11. 通知Observers:退出Loop

项目中使用

RunLoop其实在项目中常见的使用方式:线程的保活,可以采取RunLoop方式实现,比如AF中常驻线程就是采用该方式实现的;Timers滑动ScrollView失效问题,是根据RunLoop运行模式来解决。