文章目录
Runloop
OSX/iOS
系统中,提供了两个这样的对象:NSRunLoop
和 CFRunLoopRef
。
CFRunLoopRef
是在 CoreFoundation
框架内的,它提供了纯 C 函数的 API,所有这些 API 都是线程安全的。
NSRunLoop
是基于 CFRunLoopRef
的封装,提供了面向对象的 API,但是这些 API 不是线程安全的。
CFRunLoopRef
的代码是开源的,你可以在这里 http://opensource.apple.com/tarballs/CF/ 下载到整个 CoreFoundation
的源码来查看。
(Update: Swift
开源后,苹果又维护了一个跨平台的 CoreFoundation 版本:https://github.com/apple/swift-corelibs-foundation/ ,这个版本的源码可能和现有 iOS 系统中的实现略不一样,但更容易编译,而且已经适配了 Linux/Windows。)
Runloop
是属于Object Thread
线程的一部分,代码就只有两个文件CFRunloop.h
和CFRunloop.c
对于我们iOS
的工程来说,main
函数入口即是一个runloop
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
看下UIApplicationMain的说明
// NSPrincipalClass key specified, the UIApplication class is used. The delegate class will be instantiated using init.
UIKIT_EXTERN int UIApplicationMain(int argc, char * _Nullable argv[_Nonnull], NSString * _Nullable principalClassName, NSString * _Nullable delegateClassName);
其内部维持了一个runloop
,保证我们程序持续运行,不会return返回,同时处理APP中的各种事件(触摸、定时器、performSelector
)。
源码分析
创建
苹果不允许直接创建 RunLoop
,它只提供了两个自动获取的函数:CFRunLoopGetMain()
和 CFRunLoopGetCurrent()
。
static CFRunLoopRef __CFRunLoopCreate(pthread_t t) {
CFRunLoopRef loop = NULL;
CFRunLoopModeRef rlm;
uint32_t size = sizeof(struct __CFRunLoop) - sizeof(CFRuntimeBase);
loop = (CFRunLoopRef)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, __kCFRunLoopTypeID, size, NULL);
if (NULL == loop) {
return NULL;
}
(void)__CFRunLoopPushPerRunData(loop);
__CFRunLoopLockInit(&loop->_lock);
loop->_wakeUpPort = __CFPortAllocate();
if (CFPORT_NULL == loop->_wakeUpPort) HALT;
__CFRunLoopSetIgnoreWakeUps(loop);
loop->_commonModes = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
CFSetAddValue(loop->_commonModes, kCFRunLoopDefaultMode);
loop->_commonModeItems = NULL;
loop->_currentMode = NULL;
loop->_modes = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
loop->_blocks_head = NULL;
loop->_blocks_tail = NULL;
loop->_counterpart = NULL;
loop->_pthread = t;
#if DEPLOYMENT_TARGET_WINDOWS
loop->_winthread = GetCurrentThreadId();
#else
loop->_winthread = 0;
#endif
rlm = __CFRunLoopFindMode(loop, kCFRunLoopDefaultMode, true);
if (NULL != rlm) __CFRunLoopModeUnlock(rlm);
return loop;
}
static CFMutableDictionaryRef __CFRunLoops = NULL;
static CFSpinLock_t loopsLock = CFSpinLockInit;
// should only be called by Foundation
// t==0 is a synonym for "main thread" that always works
CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) {
if (pthread_equal(t, kNilPthreadT)) {
t = pthread_main_thread_np();
}
__CFSpinLock(&loopsLock);
if (!__CFRunLoops) {
//__CFRunLoops是一个CFDictionary
__CFSpinUnlock(&loopsLock);
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np()); //首先创建主线程RunLoop
CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop);
if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&__CFRunLoops)) {
//这里将dic赋值给__CFRunLoops,bool OSAtomicCompareAndSwapPtrBarrier( void *oldVal, void *newVal, void * volatile *theVal )函数会在oldVal和theVal相同的情况下将oldVal存储的值修改为newVal
CFRelease(dict);
}
CFRelease(mainLoop);
__CFSpinLock(&loopsLock);
}
//从__CFRunLoops中获取当前线程的runloop
CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
__CFSpinUnlock(&loopsLock);
if (!loop) {
//不存在则创建一个newLoop,并以pthreadPointer(t)为key的形式存入__CFRunLoops
CFRunLoopRef newLoop = __CFRunLoopCreate(t);
__CFSpinLock(&loopsLock);
loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
if (!loop) {
CFDictionarySetValue(__CFRunLoops, pthreadPointer(t