深入浅出 RunLoop(五):RunLoop 与 NSTimer
2020/2/28 23:15:26
本文主要是介绍深入浅出 RunLoop(五):RunLoop 与 NSTimer,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
RunLoop 系列文章
深入浅出 RunLoop(一):初识
深入浅出 RunLoop(二):数据结构
深入浅出 RunLoop(三):事件循环机制
深入浅出 RunLoop(四):RunLoop 与线程
深入浅出 RunLoop(五):RunLoop 与 NSTimer
深入浅出 RunLoop(六):相关面试题
RunLoop 与 NSTimer
- 由前面的文章我们知道,
NSTimer
是由RunLoop
来管理的,NSTimer
其实就是CFRunLoopTimerRef
,他们之间是 toll-free bridged 的,可以相互转换; - 如果我们在子线程上使用
NSTimer
,就必须开启子线程的RunLoop
,否则定时器无法生效。
解决 tableview 滑动时 NSTimer 失效的问题
- 问题:由前面的文章我们知道,
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 函数实现
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的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2022-10-05Swift语法学习--基于协议进行网络请求
- 2022-08-17Apple开发_Swift语言地标注释
- 2022-07-24Swift 初见
- 2022-05-22SwiftUI App 支持多语种 All In One
- 2022-05-10SwiftUI 组件参数简写 All In One
- 2022-04-14SwiftUI 学习笔记
- 2022-02-23Swift 文件夹和文件操作
- 2022-02-17Swift中使用KVO
- 2022-02-08Swift 汇编 String array
- 2022-01-30SwiftUI3.0页面反向传值