运行回路
就是一个不停处理消息 如果有消息就醒来处理 消息就去休息的循环
可以这么理解 假设RunLoop就是一个对象 这个对象有需要处理的消息和事件 然后他提供了一个入口函数 参数是一个线程 他会放一个线程进来处理 会一直处在 “接受消息->等待->处理”的循环中 直到这个循环结束(比如quit消息)
主要是为了保证程序持续运行和接受用户输入 并且处理各种事件
CFRunLoop是NSRunLoop的上层封装 所以一般研究CFRunLoop


CFRunLoop是和Thread(线程)一一绑定的
NSRunLoopCommonModes本质是一个字符串 结构上好像类是于一个数组
NSRunLoopCommonModes 包含了NSDefaultRunLoopMode UITrackingRunLoopMode UIInitializationRunLoopMode
可以手动将自己的mode加入到NSRunLoopCommonModes中
反正就是有一个RunLoop对象 然后一个进程会对应一个RunLoop对象 再往RunLoop里吗放timer什么
struct __CFRunLoop {
CFRuntimeBase _base;
pthread_mutex_t _lock; /* locked for accessing mode list */
__CFPort _wakeUpPort; // used for CFRunLoopWakeUp 通过这个来唤醒runloop
Boolean _unused;
volatile _per_run_data *_perRunData; // reset for runs of the run loop
pthread_t _pthread; //该线程和RunLoop是一一对应的关系 线程的底层都是pthread_t
uint32_t _winthread;
CFMutableSetRef _commonModes; // 存放的commonModes集合
CFMutableSetRef _commonModeItems;//timer source oberver作为item被存放在这里
CFRunLoopModeRef _currentMode;
CFMutableSetRef _modes;
struct _block_item *_blocks_head;
struct _block_item *_blocks_tail;
CFAbsoluteTime _runTime;
CFAbsoluteTime _sleepTime;
CFTypeRef _counterpart;
};
在这里存放了_sources0和_sources1 ,_timers,_observers
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 */
};
应用从操作系统(窗口服务器)中接受鼠标点击等事件的消息,并将其转到相应的例行程序来处理,如此反复,这样的过程称为运行回路
比如说当button被点击的时候操作系统会发出Action消息 然后UIApplicaion类会根据这个消息选择对应的处理对象发送给他
主运行回路会在启动事件处理方法时生成一个自动释放池
一个RunLoop可以有若干个mode mode包含source time oberver
每一次调用RunLoop主函数只能指定其中一个Mode 这个Mode就是CurrentMode 要切换Mode只能退出Loop 重新制定 目的是分割不同mode的source time oberver

分为Source0和Source1
source0不具备主动唤醒能力 source0是可以创建API接口什么的 添加到当前runloop中
基于port端口事件 可以主动唤醒线程 并且source1是没有定义API接口供我们操作
CFRunLoop是NSRunLoop的上层封装
CFRunLoopRef 是在 CoreFoundation 框架内的,它提供了纯 C 函数的 API 线程安全
NSRunLoop 是基于 CFRunLoopRef 的封装 线程不安全
线程和RunLoop是一一对应的 这是由于会创建一个全局的Dictionary(static CFMutableDictionaryRef loopsDic) 用来存储RunLoop和thread
比如在通过_CFRunLoopGet获取RunLoop的时候 如果是第一次创建 也就是loopsDic是空的 没有 就会创建一个
loopsDic = CFDictionaryCreateMutable();
CFRunLoopRef mainLoop = _CFRunLoopCreate();
CFDictionarySetValue(loopsDic, pthread_main_thread_np(), mainLoop);//然后将这个loop和主线程绑定
如果有 就会在这个dictionary根据thread作为key 去匹配 RunLoop
系统会自动开启主线程的RunLoop 保证程序不会提出
子线程的RunLoop需要手动开启
通过 pthread_main_thread_np() 或 [NSThread mainThread] 来获取主线程;也可以通过 pthread_self() 或 [NSThread currentThread] 来获取当前线程
//OC方法
NSRunLoop *runloop = [NSRunLoop currentRunLoop]; // 获得当前线程的RunLoop对象 此时会创建RunLoop
[NSRunLoop mainRunLoop]; // 获得主线程的RunLoop对象
//C语言方法
CFRunLoopGetCurrent(); // 获得当前线程的RunLoop对象
CFRunLoopGetMain(); // 获得主线程的RunLoop对象