深入浅出 RunLoop(一):初识
深入浅出 RunLoop(二):数据结构
深入浅出 RunLoop(三):事件循环机制
深入浅出 RunLoop(四):RunLoop 与线程
深入浅出 RunLoop(五):RunLoop 与 NSTimer
深入浅出 RunLoop(六):相关面试题
NSTimer
是由RunLoop
来管理的,NSTimer
其实就是CFRunLoopTimerRef
,他们之间是 toll-free bridged 的,可以相互转换;NSTimer
,就必须开启子线程的RunLoop
,否则定时器无法生效。RunLoop
同一时间只能运行在一种模式下,当我们滑动tableview
/scrollview
的时候RunLoop
会切换到UITrackingRunLoopMode
界面追踪模式下。如果我们的NSTimer
是添加到RunLoop
的KCFRunLoopDefaultMode
/NSDefaultRunLoopMode
默认模式下的话,此时是会失效的。NSTimer
添加到RunLoop
的KCFRunLoopCommonModes
/NSRunLoopCommonModes
通用模式下,来保证无论在默认模式还是界面追踪模式下NSTimer
都可以执行。NSTimer
的创建方式如果我们是通过以下方法创建的NSTimer
,是默认添加到RunLoop
的默认模式下的
[NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) { NSLog(@"123"); }]; 复制代码
我们可以通过以下方法创建NSTimer
,来自定义添加到RunLoop
的某种模式下
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) { NSLog(@"123"); }]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; 复制代码
CFRunLoopAddTimer()
函数中会判断传入的modeName
模式名称是不是
kCFRunLoopCommonModes
通用模式,是的话就会将timer
添加到RunLoop
的 _commonModeItems 集合中,并同步该timer
到 _commonModes 里的所有模式中,这样无论在默认模式还是界面追踪模式下NSTimer
都可以执行。
void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) { CHECK_FOR_FORK(); if (__CFRunLoopIsDeallocating(rl)) return; if (!__CFIsValid(rlt) || (NULL != rlt->_runLoop && rlt->_runLoop != rl)) return; __CFRunLoopLock(rl); if (modeName == kCFRunLoopCommonModes) { // 判断 modeName 是不是 kCFRunLoopCommonModes CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL; if (NULL == rl->_commonModeItems) { // 懒加载,判断 _commonModeItems 是否为空,是的话创建 rl->_commonModeItems = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); } CFSetAddValue(rl->_commonModeItems, rlt); // 将 timer 添加到 _commonModeItems 中 if (NULL != set) { CFTypeRef context[2] = {rl, rlt}; // 将 timer 和 RunLoop 封装到 context 中 /* add new item to all common-modes */ // 遍历 commonModes,将 timer 添加到 commonModes 的所有模式下 CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context); CFRelease(set); } ...... } } static void __CFRunLoopAddItemToCommonModes(const void *value, void *ctx) { CFStringRef modeName = (CFStringRef)value; CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]); CFTypeRef item = (CFTypeRef)(((CFTypeRef *)ctx)[1]); if (CFGetTypeID(item) =这篇关于深入浅出 RunLoop(五):RunLoop 与 NSTimer的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!