10、Runloop

50 阅读2分钟

CFRunLoopModeRef顾名思义,运行循环,在运行过程中循环做一些事情

Runloop的基本作用:

保持程序的持续运行

处理App中的各种事件

节省CPU资源,提高程序性能

Runloop实现需要基于Runloop,在iOS中有2套API来访问和使用Runloop

Foundation:NSRunLloop

Core Foundation: CFRunLoopRef

获取一个Runloop对象

每条线程都有唯一的一个与之对应Runloop对象

Runloop保存在一个全局的Dictionary里,线程作为key,Runloop作为value

线程在刚刚创建时并没有Runloop对象,Runloop会在第一次获取它时创建

Runloop会在线程结束时销毁

主线程的Runloop已经自动创建,子线程默认没有开启Runloop

可以通过打印测试当前只有一条线程时对应的Runloop,如下图所示

通过源码CFRunLoop的源码可以得知会调用_CFRunLoopGet0

从图中可以得知Runloop是存放在Dictionary中,线程作为key,在Runloop为空时会调用创建方法

_ _CFRunLoop结构体的基本结构如下图所示

其中最主要为CFRunLoopMode

Mode又包含着对应的source、observer、和timer

通过源码解析RunLoop具体流程,由于RunLoop会处理点击事件,通过touchesBegin打断点就可以找到RunLoop的入口

可以在RunLoop源码中找到

第一步通知Observers:进入循环(前面的锁和mode部分忽略)

第二步RunLoop Run起来,具体要做的事情

接下来是退出RunLoop

接下来查看一下_ _CFRunLoopRun里面做了什么

可以发现有一个do-while,返回值如果是0则会循环执行

首先仍然是通知Observer,即将处理timer,接下来是即将处理source

接下来是处理blocks,然后处理Source0,如果结果为YES则再处理一次blocks

接下来是处理source1,判断如果有source1则跳转到 handle_msg(通过端口处理相关线程内容)

接下来仍然是通知Observer,但这次是即将进入等待之前,接下来就进入休眠

下一步等待别的消息来唤醒线程

通知Observer:结束休眠

处理timer,被timer唤醒

或者被GCD唤醒,处理GCD相关

或者是被source1唤醒,处理source1

又处理blocks,最后判断返回值,如果为0则循环执行

如果不为0则跳转到result,通知Observer退出RunLoop