tableView加载过多的高清大图,Runloop不只处理iOS事件,渲染图形也是runloop处理的。
Source1/Timer/Observer _currentMode:RunLoop当前的运行模式 _modes:存储着RunLoop所有的 Mode(CFRunLoopModeRef)模式 // CFRunLoop.h typedef struct __CFRunLoop * CFRunLoopRef; // CFRunLoop.c struct __CFRunLoop { pthread_t _pthread // CFRunLoop.h typedef struct __CFRunLoopMode *CFRunLoopModeRef; // CFRunLoop.c struct __CFRunLoopMode // CFRunLoop.h typedef struct __CFRunLoopSource * CFRunLoopSourceRef; // CFRunLoop.m struct __CFRunLoopSource // CFRunLoop.h typedef struct CF_BRIDGED_MUTABLE_TYPE(NSTimer) __CFRunLoopTimer * CFRunLoopTimerRef;
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopBeforeTimers); /// 3. __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopBeforeSources); __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(source0); __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK 通知Observers,线程被唤醒 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopAfterWaiting 如果是被Timer唤醒的,回调Timer __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__(timer);
一、CFRunLoop部分源码 阅读源码:CFRunLoop.c CFRunLoopRef CFRunLoopGetCurrent(void) { CHECK_FOR_FORK(); CFRunLoopRef RunLoop有5个类 CFRunLoopRef CFRunLoopModelRef CFRunLoopSourceRef CFRunLoopTimerRef CFRunLoopObserverRef 2、CFRunLoop struct __CFRunLoop { CFRuntimeBase _base; pthread_mutex_t _lock; /* locked for accessing mode = MACH_PORT_NULL && livePort == modeQueuePort) { CFRUNLOOP_WAKEUP_FOR_TIMER(); = MACH_PORT_NULL && livePort == rlm->_timerPort) { CFRUNLOOP_WAKEUP_FOR_TIMER();
处理消息 handle_msg:; if(MACH_PORT_NULL == livePort) { CFRUNLOOP_WAKEUP_FOR_NOTHING (); } else if(livePort == rl->_wakeUpPort) { CFRUNLOOP_WAKEUP_FOR_WAKEUP(); = MACH_PORT_NULL && livePort == modeQueuePort) { // 处理定时器事件 CFRUNLOOP_WAKEUP_FOR_TIMER (); } else if(livePort == dispatchPort) { // 处理主线程消息 CFRUNLOOP_WAKEUP_FOR_DISPATCH (); } else { // 处理 sources1 CFRUNLOOP_WAKEUP_FOR_SOURCE(); }
可以从CF框架源码 的 CFRunLoop.h和CFRunLoop.c,看看 苹果对 CFRunLoopRef 的定义。 CFRunLoopRef是 结构体__CFRunLoop *的重命名,由 typedef struct __CFRunLoop * CFRunLoopRef; 可知; __CFRunLoop 的定义: struct __CFRunLoop { CFRuntimeBase _base; pthread_mutex_t _lock; /* locked for accessing timerSoftDeadline; /* TSR */ uint64_t _timerHardDeadline; /* TSR */ }; 看完上面 __CFRunLoopMode 和 __CFRunLoop else if (msg_is_dispatch) { __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg);
_CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION_(kCFRunloopBeforeSources); _CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK _CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION_(source0); /// 5. GCD处理main block; _CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(block); /// 6. 如果是被timer唤醒的,回调timer _CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION(timer); /// _CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__(source1); } while (...); /// 10.
接下来查看一下CFRunLoopRef具体的数据结构如下: struct __CFRunLoop { CFRuntimeBase _base; pthread_mutex_t _lock RunLoop数据结构 上图很好的描述了struct __CFRunLoop数据结构相关成员变量的关系,每一个__CFRunLoop对象可以包含数个不同的Mode,而每一个Mode又包含了数个Source 中比较重要的几个成员变量: struct __CFRunLoop { ... __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopBeforeSources); __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(source0); __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK
无处不在的runloop 我们上图中,调用栈中有一个很长的函数——__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__。 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ // 处理timer回调 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0 RunLoop结构 通过上图可以看出: 一个thread对应一个runloop Cocoa层的NSRunLoop是对CF层的CFRunLoop的封装 一个runloop对应多个runLoopMode 一个 RunLoop结构体定义 // RunLoop的结构体定义 struct __CFRunLoop { pthread_mutex_t _lock; // 其中的RCTMessageThread就是C++对CFRunloop的封装。 其他有使用runLoop的地方还有卡顿监控、异步绘制等。
的callback指针,通知runloop的activity状态变化 __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ // 处理添加到runloop 的block __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ // 处理分发给主线程的事件 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION __ // 处理timer回调 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ // 处理source0回调 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1 runLoop 结构 runLoop的结构如下图所示: [runloop结构] 通过上图可以看出: 一个thread对应一个runloop Cocoa层的NSRunLoop是对CF层的CFRunLoop 其中的RCTMessageThread就是C++对CFRunloop的封装。 其他有使用runLoop的地方还有卡顿监控、异步绘制等。
本文转自ibireme的《深入理解RunLoop》 RunLoop 是 iOS 和 OSX 开发中非常基础的一个概念,这篇文章将从 CFRunLoop 的源码入手,介绍 RunLoop 的概念以及底层实现原理 CFRunLoop 是基于 pthread 来管理的。 如果一个 mode 中一个 item 都没有,则 RunLoop 会直接退出,不进入循环 RunLoop 的 Mode CFRunLoopMode 和 CFRunLoop 的结构大致如下: struct __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopBeforeSources); __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(source0); __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK
--- runLoop是如何实现的 首先要明确的一点事,在平时我们使用的是Foundation框架的NSRunLoop类去做一些实现,而其实NSRunLoop是基于CoreFoundation框架中的CFRunLoop 所以我们这里着重介绍CFRunLoop,毕竟我们能拿到CFRunLoop的源码。 1.runLoop的组成 struct __CFRunLoop { CFRuntimeBase _base; pthread_mutex_t _lock; /* locked block_item *_blocks_head; struct _block_item *_blocks_tail; CFTypeRef _counterpart; }; 我们大概可以CFRunLoop = MACH_PORT_NULL && livePort == rlm->_timerPort) {//处理定时器事件 CFRUNLOOP_WAKEUP_FOR_TIMER();
如果找到CFRunloop的源码,我们可以看到,CFRunloop.c的源码也就3900行左右。所以说Runloop其实比Runtime要简单多了! CFRunloopRef的定义如下: typedef struct CF_BRIDGED_MUTABLE_TYPE(id) __CFRunLoop * CFRunLoopRef; 这说明,CFRunLoopRef 是一个指向__CFRunLoop结构体的指针,__CFRunLoop结构体的定义如下: struct __CFRunLoop { CFRuntimeBase _base; pthread_mutex_t = MACH_PORT_NULL && livePort == modeQueuePort) { CFRUNLOOP_WAKEUP_FOR_TIMER(); (); } else { CFRUNLOOP_POLL(); } //通过mach_msg发送或者接收的消息都是指针, //如果直接发送或者接收消息体,
#include <CoreFoundation/CFRunLoop.h> #include <CoreFoundation/CFSet.h> #include <CoreFoundation/CFBag.h handle_msg 中的代码片段: ...... else if (livePort == dispatchPort) { CFRUNLOOP_WAKEUP_FOR_DISPATCH(); )6, NULL); #if DEPLOYMENT_TARGET_WINDOWS void *msg = 0; #endif // 获取GCDMainQ上的异步任务并执行 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE static void __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(void *msg) { _dispatch_main_queue_callback
handle nothing } //被显示唤醒 else if (livePort == rl->_wakeUpPort) { CFRUNLOOP_WAKEUP_FOR_WAKEUP = MACH_PORT_NULL && livePort == modeQueuePort) { CFRUNLOOP_WAKEUP_FOR_TIMER(); = MACH_PORT_NULL && livePort == rlm->_timerPort) { CFRUNLOOP_WAKEUP_FOR_TIMER(); 函数,调用主队列来执行任务,这个任务就在这里处理 */ else if (livePort == dispatchPort) { CFRUNLOOP_WAKEUP_FOR_DISPATCH didDispatchPortLastTime = true; } //处理source1事件 else { CFRUNLOOP_WAKEUP_FOR_SOURCE
(rl, rlm, mach_absolute_time()) } else if (被 GCD 唤醒) { // 处理 GCD __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE msg->msgh_size = buffer_size; msg->msgh_id = 0; if (TIMEOUT_INFINITY == timeout) { CFRUNLOOP_SLEEP (); } else { CFRUNLOOP_POLL(); } // ⚠️⚠️⚠️ ret = mach_msg(msg, MACH_RCV_MSG|(voucherState voucher_copy(); } else { *voucherCopy = NULL; } } CFRUNLOOP_WAKEUP
我们来看下 CFRunloop 以及 CFRunloopMode的定义: ? 正如上面介绍的,CFRunloopMode 是由几种mode item的集合构成的,而CFRunloop 又包含若干个CFRunloopMode。 CFRunloop中还定义了commonModes 和 commonModeItems 两个集合,这里有个介绍: 可以将一个mode标记为common属性,也就是调用下面这个接口将mode加入到_commonModes CFRunloop.c 的源码可以在这里https://opensource.apple.com/source/CF/CF-855.17/CFRunLoop.c.auto.html看到,下面是关键部分的源代码
CFRunLoop 是基于 pthread 来管理的。 1.4 RunLoop的Mode CFRunLoopMode和CFRunLoop的结构大致如下: struct __CFRunLoopMode { // Mode Name, 例如 else if (msg_is_dispatch) { __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg); __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopBeforeSources); __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(source0); __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK
RunLoop结构体 通过源码我们找到__CFRunLoop结构体 struct __CFRunLoop { CFRuntimeBase _base; pthread_mutex_t _ __CFRunLoopDoObservers 内部调用 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ __CFRunLoopDoBlocks 内部调用 __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ __CFRunLoopDoSources0 内部调用 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0 _PERFORM_FUNCTION__ __CFRunLoopDoTimers 内部调用 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION __ GCD 调用 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ __CFRunLoopDoSource1 内部调用 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1
__(); static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(); static void __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE __(); static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__(); static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0 _PERFORM_FUNCTION__(); static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__(); Observer __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__() } else { __CFRunLoopDoSource1(); timeout); //通知observers,即将退出runloop __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBERVER_CALLBACK_FUNCTION__(CFRunLoopExit