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