RunLoop概念
运行循环,一个 run loop 就是一个事件处理的循环,用来不停的调度工作以及处理事件
作用
- 保持程序的持续运行
- 监听处理App中的各种事件(触摸事件,定时器事件,selector事件)
- 节省CPU资源,提高程序性能:该做事时做事,该休息时休息
- 一次RunLoop循环负责绘制屏幕上所有的点
入口函数
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
UIApplicationMain()此函数内部就启动了一个RunLoop,所以此函数一直没有返回,保持了程序的持续运行,这个默认启动的RunLoop是跟主线程相关的
RunLoop对象
- Foundation框架下 : NSRunLoop (基于 CFRunLoopRef 的封装,提供了面向对象的 API,但是这些 API 不是线程安全的)
- Core Foundation框架下 : CFRunLoopRef (纯 C 函数的 API,所有这些 API 都是线程安全的)
RunLoop与线程
- 每条线程有唯一的一个与之对应的RunLoop对象
- 主线程的RunLoop已经自动创建好了,子线程的RunLoop需要手动创建
- RunLoop在第一次获取时创建,在线程结束时销毁
NSRunLoop *currentRunloop = [NSRunLoop currentRunLoop];//主线程对应的RunLoop
[NSRunLoop mainRunLoop];//当前线程对应的RunLoop
currentRunloop.getCFRunLoop;//转化为CFRunLoop
CFRunLoopGetMain(); CFRunLoopGetCurrent(); //开启一个子线程
[[[NSThread alloc]initWithTarget:self selector:@selector(run) object:nil] start]; -(void)run { //创建子线程对应的RunLoop,currentRunLoop 懒加载的
[NSRunLoop currentRunLoop]; }
以下是苹果官方源码,通过分析源代码可以看出利用pthread作为全局字典中的key,并创建与之对应的RunLoop作为Value,RunLoop在我们获取的时候创建,不获取不创建,主线程的RunLoop在一开始就自动创建。线程与RunLoop是一一对应的关系
CFRunLoopRef CFRunLoopGetMain(void) { CHECK_FOR_FORK(); static CFRunLoopRef __main = NULL; // no retain needed
if (!__main) __main = _CFRunLoopGet0(pthread_main_thread_np()); // no CAS needed
return __main; } CFRunLoopRef CFRunLoopGetCurrent(void) { CHECK_FOR_FORK(); CFRunLoopRef rl = (CFRunLoopRef)_CFGetTSD(__CFTSDKeyRunLoop); if (rl) return rl; return _CFRunLoopGet0(pthread_self()); } //全局的Dictionary,key 是 pthread_t, value 是 CFRunLoopRef
static CFMutableDictionaryRef __CFRunLoops = NULL; //访问 Dictionary 时的锁
static CFLock_t loopsLock = CFLockInit; //获取一个 pthread 对应的 RunLoop
CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) { //如果传进来的线程等于 0
if (pthread_equal(t, kNilPthreadT)) { //当前线程等于主线程
t = pthread_main_thread_np(); } //给操作加锁
__CFLock(&loopsLock); //如果当前RunLoop为空,创建。
if (!__CFRunLoops) { __CFUnlock(&loopsLock); // 创建字典
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks); // 创建主线程
CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np()); // 保存主线程
CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop); if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&__CFRunLoops)) { CFRelease(dict); } CFRelease(mainLoop); __CFLock(&loopsLock); } // 从字典中获取当前线程的RunLoop
CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t)); __CFUnlock(&loopsLock); if (!loop) { // 如果当前线程的runloop不存在,那么就为该线程创建一个对应的runloop
CFRunLoopRef newLoop = __CFRunLoopCreate(t); __CFLock(&loopsLock); loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t)); // 把当前子线程和对应的runloop保存到字典中
if (!loop) { CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop); loop = newLoop; } // don't release run loops inside the loopsLock, because CFRunLoopDeallocate may end up taking it
__CFUnlock(&loopsLock); CFRelease(newLoop); } if (pthread_equal(t, pthread_self())) { _CFSetTSD(__CFTSDKeyRunLoop, (void *)loop, NULL); if (0 == _CFGetTSD(__CFT