- 小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
写在前面: iOS底层原理探究是本人在平时的开发和学习中不断积累的一段进阶之
路的。 记录我的不断探索之旅,希望能有帮助到各位读者朋友。
目录如下:
- iOS 底层原理探索 之 alloc
- iOS 底层原理探索 之 结构体内存对齐
- iOS 底层原理探索 之 对象的本质 & isa的底层实现
- iOS 底层原理探索 之 isa - 类的底层原理结构(上)
- iOS 底层原理探索 之 isa - 类的底层原理结构(中)
- iOS 底层原理探索 之 isa - 类的底层原理结构(下)
- iOS 底层原理探索 之 Runtime运行时&方法的本质
- iOS 底层原理探索 之 objc_msgSend
- iOS 底层原理探索 之 Runtime运行时慢速查找流程
- iOS 底层原理探索 之 动态方法决议
- iOS 底层原理探索 之 消息转发流程
- iOS 底层原理探索 之 应用程序加载原理dyld (上)
- iOS 底层原理探索 之 应用程序加载原理dyld (下)
- iOS 底层原理探索 之 类的加载
- iOS 底层原理探索 之 分类的加载
- iOS 底层原理探索 之 关联对象
- iOS底层原理探索 之 魔法师KVC
- iOS底层原理探索 之 KVO原理|8月更文挑战
- iOS底层原理探索 之 重写KVO|8月更文挑战
- iOS底层原理探索 之 多线程原理|8月更文挑战
- iOS底层原理探索 之 GCD函数和队列
- iOS底层原理探索 之 GCD原理(上)
- iOS底层 - 关于死锁,你了解多少?
- iOS底层 - 单例 销毁 可否 ?
- iOS底层 - Dispatch Source
- iOS底层 - 一个栅栏函 拦住了 数
- iOS底层 - 不见不散 的 信号量
- iOS底层 GCD - 一进一出 便成 调度组
- iOS底层原理探索 - 锁的基本使用
- iOS底层 - @synchronized 流程分析
- iOS底层 - 锁的原理探索
- iOS底层 - 带你实现一个读写锁
- iOS底层 - 谈Objective-C block的实现(上)
- iOS底层 - 谈Objective-C block的实现(下)
- iOS底层 - Block, 全面解析!
- iOS底层 - 启动优化(上)
- iOS底层 - 启动优化(下)
- iOS底层原理探索 -- 内存管理 之 内存五大区
- iOS底层原理探索 -- 内存管理 之 Tagged Pointer Format Changes
- iOS底层原理探索 -- 内存管理 之 retain & release
- iOS底层原理探索 -- 内存管理 之 弱引用表
- iOS底层原理探索 -- 内存管理 之 @autoreleasepool
- iOS底层原理探索 之 RunLoop 概念
以上内容的总结专栏
细枝末节整理
前言
上一篇我们主要讲解了runloop的相关概念介绍,今天,我们从底层的角度,开始深入剖析 RunLoop 的结构和实现原理。
RunLoop 的作用
- Runloop 可以保持我们的程序持续的运行;
- 处理App中的各种事件(触摸,定时器,performSelect);
- 节省CPU资源:该工作就工作,该休息就休息。
RunLoop 的数据结构
通过下符号断点,我们可以定位到 RunLoop 源码在 CoreFoundation 中。
打开 CoreFoundation 的源码 :
底层是 do {} while () 循环实现
void CFRunLoopRun(void) { /* DOES CALLOUT */
int32_t result;
do {
result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false);
CHECK_FOR_FORK();
} while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result);
}
CFRunLoopRef CFRunLoopGetCurrent(void) {
CHECK_FOR_FORK();
CFRunLoopRef rl = (CFRunLoopRef)_CFGetTSD(__CFTSDKeyRunLoop);
if (rl) return rl;
return _CFRunLoopGet0(pthread_self());
}
线程和runloop是一一对应的关系
CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) {
if (pthread_equal(t, kNilPthreadT)) {
//主线程
t = pthread_main_thread_np();
}
__CFLock(&loopsLock);
if (!__CFRunLoops) {
__CFUnlock(&loopsLock);
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np());
// 进行绑定 dict[@"pthread_main_thread_np"] = mainLoop
CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop);
...
if (!loop) {
// 通过线程 创建 runloop
CFRunLoopRef newLoop = __CFRunLoopCreate(t);
__CFLock(&loopsLock);
loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
if (!loop) {
//没有获取到就存储线程和runloop
CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);
loop = newLoop;
}
...
return loop;
}
__CFRunLoop
runloop 包含多个 mode 和 item ;包含线程信息;
struct __CFRunLoop {
CFRuntimeBase _base;
pthread_mutex_t _lock; /* locked for accessing mode list */
__CFPort _wakeUpPort; // used for CFRunLoopWakeUp
Boolean _unused;
volatile _per_run_data *_perRunData; // reset for runs of the run loop
pthread_t _pthread;
uint32_t _winthread;
CFMutableSetRef _commonModes;
CFMutableSetRef _commonModeItems;
CFRunLoopModeRef _currentMode;
CFMutableSetRef _modes;
struct _block_item *_blocks_head;
struct _block_item *_blocks_tail;
CFAbsoluteTime _runTime;
CFAbsoluteTime _sleepTime;
CFTypeRef _counterpart;
};
系统默认注册了 5 个 Mode:
kCFRunLoopDefaultMode
: App 的默认 Mode,通常主线程是在这个 Mode 下面运行的UITrackingRunLoopMode
: 界面跟踪 Mode,用于 ScrollView 追踪触摸滑动UIInitializationRunLoopMode
: 在刚启动 App 时进入的第一个 Mode,启动完后就不再使用GSEventReceiveRunLoopMode
: 接受系统事件的内部 Mode,通常用不到kCFRunLoopCommonModes
: 这是一个占位的 Mode,没有实际作用
__CFRunLoopMode
mode 包含多个_sources0、_sources1、_observers和_timers
typedef struct __CFRunLoopMode *CFRunLoopModeRef;
struct __CFRunLoopMode {
CFRuntimeBase _base;
pthread_mutex_t _lock; /* must have the run loop locked before locking this */
CFStringRef _name;
Boolean _stopped;
char _padding[3];
CFMutableSetRef _sources0;
CFMutableSetRef _sources1;
CFMutableArrayRef _observers;
CFMutableArrayRef _timers;
CFMutableDictionaryRef _portToV1SourceMap;
__CFPortSet _portSet;
CFIndex _observerMask;
#if USE_DISPATCH_SOURCE_FOR_TIMERS
dispatch_source_t _timerSource;
dispatch_queue_t _queue;
Boolean _timerFired; // set to true by the source when a timer has fired
Boolean _dispatchTimerArmed;
#endif
#if USE_MK_TIMER_TOO
mach_port_t _timerPort;
Boolean _mkTimerArmed;
#endif
#if DEPLOYMENT_TARGET_WINDOWS
DWORD _msgQMask;
void (*_msgPump)(void);
#endif
uint64_t _timerSoftDeadline; /* TSR */
uint64_t _timerHardDeadline; /* TSR */
};
也就是 items (_sources0、_sources1、_observers和_timers) 依赖于 mode 在runloop 中执行。
今天看到一片很好的runloop文章,在这里分享给大家: www.cocoachina.com/articles/11…