NSTimer的精确度
1、iOS中一般UI上面常用两种定时器 NSTimer和CADisplayLink,那么它们分别的精确度是如何呢?
CADisplayLink 是用于帧刷新定时器,也就是和界面的刷新率保持一致,理想情况下FPS为60,并尽力保持60
NSTimer是否可以比CADisplayLink更加精确呢,最精确能下面的间隔是多少呢?NSTimer和CADisplayLink都作为一种事件加入到NSRunloop的事件源中,
NSRunloop不断循环,判断是否应该触发这一类事件,如下面所示,NSRunloop包涵下面这些不同的事件:
1 2 3 4 5 6 7 8 | typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) { kCFRunLoopEntry = (1UL << 0), // 即将进入Loop kCFRunLoopBeforeTimers = (1UL << 1), // 即将处理 Timer kCFRunLoopBeforeSources = (1UL << 2), // 即将处理 Source kCFRunLoopBeforeWaiting = (1UL << 5), // 即将进入休眠 kCFRunLoopAfterWaiting = (1UL << 6), // 刚从休眠中唤醒 kCFRunLoopExit = (1UL << 7), // 即将退出Loop }; |
可以看出,如果想让CADisplayLink正常工作,NSRunloop至少每秒循环60次,也就是至多17ms,那么NSRunloop每秒最多循环多少次呢?
2、NSRunloop每秒循环多少次
通过注册一个观察者到主线程中,观察每一种事件执行的log,来看看NSRunloop的执行情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | - ( BOOL )application:(UIApplication *)application didFinishLaunchingWithOptions:( NSDictionary *)launchOptions { // Override point for customization after application launch. CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler( NULL , (kCFRunLoopAllActivities), YES , 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) { static unsigned long count = 0; if (activity & kCFRunLoopEntry) { NSLog (@ "activity %lu: %@" , ++count, @ "kCFRunLoopEntry" ); } else if (activity & kCFRunLoopBeforeTimers) { NSLog (@ "activity %lu: %@" , ++count, @ "kCFRunLoopBeforeTimers" ); } else if (activity & kCFRunLoopBeforeSources) { NSLog (@ "activity %lu: %@" , ++count, @ "kCFRunLoopBeforeSources" ); } else if (activity & kCFRunLoopBeforeWaiting) { NSLog (@ "activity %lu: %@" , ++count, @ "kCFRunLoopBeforeWaiting" ); } else if (activity & kCFRunLoopAfterWaiting) { NSLog (@ "activity %lu: %@" , ++count, @ "kCFRunLoopAfterWaiting" ); } else if (activity & kCFRunLoopExit) { NSLog (@ "activity %lu: %@" , ++count, @ "kCFRunLoopExit" ); } }); CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes); return YES ; } |
这里打印出每一类的事件,同时需要加上两类定时器到主线程中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | - ( void )viewDidLoad { [ super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. NSTimer *timer = [ NSTimer timerWithTimeInterval:0.001 repeats: YES block:^( NSTimer * _Nonnull timer) { static int timerCount = 0; //do nothing NSLog (@ "timer do nothing, timerCount = %d" , timerCount++); }]; [[ NSRunLoop currentRunLoop] addTimer:timer forMode: NSRunLoopCommonModes ]; CADisplayLink *link = [CADisplayLink displayLinkWithTarget: self selector: @selector (update:)]; [link addToRunLoop:[ NSRunLoop currentRunLoop] forMode: NSRunLoopCommonModes ]; } - ( void )update:( id )sender { static int linkCount = 0; NSLog (@ "link do nothing, linkCount = %d" , linkCount++); } |
可以观察出每一类事件执行的情况,测试是在iphone5s, ios10.2的系统上
输出:
NSRunloop:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 2017-03-18 13:01:54.145100 NSTimerTest [1121:267663] activity 20: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.148893 NSTimerTest [1121:267663] activity 24: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.150659 NSTimerTest [1121:267663] activity 28: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.153758 NSTimerTest [1121:267663] activity 32: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.155796 NSTimerTest [1121:267663] activity 36: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.158515 NSTimerTest [1121:267663] activity 40: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.160481 NSTimerTest [1121:267663] activity 44: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.162514 NSTimerTest [1121:267663] activity 48: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.165265 NSTimerTest [1121:267663] activity 52: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.169531 NSTimerTest [1121:267663] activity 56: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.229129 NSTimerTest [1121:267663] activity 74: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.232630 NSTimerTest [1121:267663] activity 78: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.233628 NSTimerTest [1121:267663] activity 82: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.235007 NSTimerTest [1121:267663] activity 86: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.236381 NSTimerTest [1121:267663] activity 90: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.237788 NSTimerTest [1121:267663] activity 94: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.238881 NSTimerTest [1121:267663] activity 98: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.239719 NSTimerTest [1121:267663] activity 102: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.240767 NSTimerTest [1121:267663] activity 106: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.241759 NSTimerTest [1121:267663] activity 110: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.242658 NSTimerTest [1121:267663] activity 114: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.243716 NSTimerTest [1121:267663] activity 118: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.244833 NSTimerTest [1121:267663] activity 122: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.245719 NSTimerTest [1121:267663] activity 126: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.247445 NSTimerTest [1121:267663] activity 130: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.248342 NSTimerTest [1121:267663] activity 134: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.250020 NSTimerTest [1121:267663] activity 138: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.251359 NSTimerTest [1121:267663] activity 142: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.252876 NSTimerTest [1121:267663] activity 146: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.254850 NSTimerTest [1121:267663] activity 150: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.256126 NSTimerTest [1121:267663] activity 154: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.257336 NSTimerTest [1121:267663] activity 158: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.258301 NSTimerTest [1121:267663] activity 162: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.259885 NSTimerTest [1121:267663] activity 166: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.261638 NSTimerTest [1121:267663] activity 170: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.262796 NSTimerTest [1121:267663] activity 174: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.264645 NSTimerTest [1121:267663] activity 178: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.265702 NSTimerTest [1121:267663] activity 182: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.266818 NSTimerTest [1121:267663] activity 186: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.268355 NSTimerTest [1121:267663] activity 190: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.269167 NSTimerTest [1121:267663] activity 194: kCFRunLoopBeforeWaiting 2017-03-18 13:01:54.269909 NSTimerTest [1121:267663] activity 198: kCFRunLoopBeforeWaiting |
NSTimer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | 2017-03-18 13:01:54.127460 NSTimerTest [1121:267663] timer do nothing, timerCount = 0 2017-03-18 13:01:54.135893 NSTimerTest [1121:267663] timer do nothing, timerCount = 1 2017-03-18 13:01:54.140639 NSTimerTest [1121:267663] timer do nothing, timerCount = 2 2017-03-18 13:01:54.142266 NSTimerTest [1121:267663] timer do nothing, timerCount = 3 2017-03-18 13:01:54.143658 NSTimerTest [1121:267663] timer do nothing, timerCount = 4 2017-03-18 13:01:54.147695 NSTimerTest [1121:267663] timer do nothing, timerCount = 5 2017-03-18 13:01:54.151489 NSTimerTest [1121:267663] timer do nothing, timerCount = 6 2017-03-18 13:01:54.154552 NSTimerTest [1121:267663] timer do nothing, timerCount = 7 2017-03-18 13:01:54.156480 NSTimerTest [1121:267663] timer do nothing, timerCount = 8 2017-03-18 13:01:54.159303 NSTimerTest [1121:267663] timer do nothing, timerCount = 9 2017-03-18 13:01:54.161246 NSTimerTest [1121:267663] timer do nothing, timerCount = 10 2017-03-18 13:01:54.163655 NSTimerTest [1121:267663] timer do nothing, timerCount = 11 2017-03-18 13:01:54.170411 NSTimerTest [1121:267663] timer do nothing, timerCount = 12 2017-03-18 13:01:54.226209 NSTimerTest [1121:267663] timer do nothing, timerCount = 13 2017-03-18 13:01:54.228032 NSTimerTest [1121:267663] timer do nothing, timerCount = 14 2017-03-18 13:01:54.231912 NSTimerTest [1121:267663] timer do nothing, timerCount = 15 2017-03-18 13:01:54.234140 NSTimerTest [1121:267663] timer do nothing, timerCount = 16 2017-03-18 13:01:54.235779 NSTimerTest [1121:267663] timer do nothing, timerCount = 17 2017-03-18 13:01:54.236939 NSTimerTest [1121:267663] timer do nothing, timerCount = 18 2017-03-18 13:01:54.238231 NSTimerTest [1121:267663] timer do nothing, timerCount = 19 2017-03-18 13:01:54.239210 NSTimerTest [1121:267663] timer do nothing, timerCount = 20 2017-03-18 13:01:54.240251 NSTimerTest [1121:267663] timer do nothing, timerCount = 21 2017-03-18 13:01:54.241185 NSTimerTest [1121:267663] timer do nothing, timerCount = 22 2017-03-18 13:01:54.242131 NSTimerTest [1121:267663] timer do nothing, timerCount = 23 2017-03-18 13:01:54.243136 NSTimerTest [1121:267663] timer do nothing, timerCount = 24 2017-03-18 13:01:54.244139 NSTimerTest [1121:267663] timer do nothing, timerCount = 25 2017-03-18 13:01:54.245170 NSTimerTest [1121:267663] timer do nothing, timerCount = 26 2017-03-18 13:01:54.246129 NSTimerTest [1121:267663] timer do nothing, timerCount = 27 2017-03-18 13:01:54.248936 NSTimerTest [1121:267663] timer do nothing, timerCount = 28 2017-03-18 13:01:54.250729 NSTimerTest [1121:267663] timer do nothing, timerCount = 29 2017-03-18 13:01:54.252273 NSTimerTest [1121:267663] timer do nothing, timerCount = 30 2017-03-18 13:01:54.253343 NSTimerTest [1121:267663] timer do nothing, timerCount = 31 2017-03-18 13:01:54.255634 NSTimerTest [1121:267663] timer do nothing, timerCount = 32 2017-03-18 13:01:54.256494 NSTimerTest [1121:267663] timer do nothing, timerCount = 33 2017-03-18 13:01:54.257829 NSTimerTest [1121:267663] timer do nothing, timerCount = 34 2017-03-18 13:01:54.259261 NSTimerTest [1121:267663] timer do nothing, timerCount = 35 2017-03-18 13:01:54.260290 NSTimerTest [1121:267663] timer do nothing, timerCount = 36 2017-03-18 13:01:54.262144 NSTimerTest [1121:267663] timer do nothing, timerCount = 37 2017-03-18 13:01:54.263531 NSTimerTest [1121:267663] timer do nothing, timerCount = 38 2017-03-18 13:01:54.266225 NSTimerTest [1121:267663] timer do nothing, timerCount = 39 2017-03-18 13:01:54.267656 NSTimerTest [1121:267663] timer do nothing, timerCount = 40 2017-03-18 13:01:54.268629 NSTimerTest [1121:267663] timer do nothing, timerCount = 41 2017-03-18 13:01:54.269641 NSTimerTest [1121:267663] timer do nothing, timerCount = 42 2017-03-18 13:01:54.271133 NSTimerTest [1121:267663] timer do nothing, timerCount = 43 2017-03-18 13:01:54.272366 NSTimerTest [1121:267663] timer do nothing, timerCount = 44 2017-03-18 13:01:54.273213 NSTimerTest [1121:267663] timer do nothing, timerCount = 45 2017-03-18 13:01:54.274115 NSTimerTest [1121:267663] timer do nothing, timerCount = 46 2017-03-18 13:01:54.275425 NSTimerTest [1121:267663] timer do nothing, timerCount = 47 2017-03-18 13:01:54.276400 NSTimerTest [1121:267663] timer do nothing, timerCount = 48 2017-03-18 13:01:54.278951 NSTimerTest [1121:267663] timer do nothing, timerCount = 49 2017-03-18 13:01:54.281740 NSTimerTest [1121:267663] timer do nothing, timerCount = 50 2017-03-18 13:01:54.283120 NSTimerTest [1121:267663] timer do nothing, timerCount = 51 2017-03-18 13:01:54.284362 NSTimerTest [1121:267663] timer do nothing, timerCount = 52 |
CADisplayLink
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | 2017-03-18 13:01:54.138378 NSTimerTest [1121:267663] link do nothing, linkCount = 0 2017-03-18 13:01:54.149657 NSTimerTest [1121:267663] link do nothing, linkCount = 1 2017-03-18 13:01:54.166121 NSTimerTest [1121:267663] link do nothing, linkCount = 2 2017-03-18 13:01:54.225401 NSTimerTest [1121:267663] link do nothing, linkCount = 3 2017-03-18 13:01:54.233023 NSTimerTest [1121:267663] link do nothing, linkCount = 4 2017-03-18 13:01:54.247794 NSTimerTest [1121:267663] link do nothing, linkCount = 5 2017-03-18 13:01:54.265119 NSTimerTest [1121:267663] link do nothing, linkCount = 6 2017-03-18 13:01:54.280689 NSTimerTest [1121:267663] link do nothing, linkCount = 7 2017-03-18 13:01:54.298406 NSTimerTest [1121:267663] link do nothing, linkCount = 8 2017-03-18 13:01:54.315036 NSTimerTest [1121:267663] link do nothing, linkCount = 9 2017-03-18 13:01:54.331416 NSTimerTest [1121:267663] link do nothing, linkCount = 10 2017-03-18 13:01:54.346888 NSTimerTest [1121:267663] link do nothing, linkCount = 11 2017-03-18 13:01:54.363696 NSTimerTest [1121:267663] link do nothing, linkCount = 12 2017-03-18 13:01:54.380435 NSTimerTest [1121:267663] link do nothing, linkCount = 13 2017-03-18 13:01:54.398125 NSTimerTest [1121:267663] link do nothing, linkCount = 14 2017-03-18 13:01:54.414091 NSTimerTest [1121:267663] link do nothing, linkCount = 15 2017-03-18 13:01:54.430187 NSTimerTest [1121:267663] link do nothing, linkCount = 16 2017-03-18 13:01:54.447019 NSTimerTest [1121:267663] link do nothing, linkCount = 17 2017-03-18 13:01:54.463854 NSTimerTest [1121:267663] link do nothing, linkCount = 18 2017-03-18 13:01:54.480343 NSTimerTest [1121:267663] link do nothing, linkCount = 19 2017-03-18 13:01:54.513566 NSTimerTest [1121:267663] link do nothing, linkCount = 21 2017-03-18 13:01:54.530110 NSTimerTest [1121:267663] link do nothing, linkCount = 22 2017-03-18 13:01:54.547502 NSTimerTest [1121:267663] link do nothing, linkCount = 23 2017-03-18 13:01:54.565346 NSTimerTest [1121:267663] link do nothing, linkCount = 24 2017-03-18 13:01:54.580107 NSTimerTest [1121:267663] link do nothing, linkCount = 25 2017-03-18 13:01:54.598014 NSTimerTest [1121:267663] link do nothing, linkCount = 26 2017-03-18 13:01:54.629988 NSTimerTest [1121:267663] link do nothing, linkCount = 28 2017-03-18 13:01:54.646657 NSTimerTest [1121:267663] link do nothing, linkCount = 29 2017-03-18 13:01:54.663800 NSTimerTest [1121:267663] link do nothing, linkCount = 30 2017-03-18 13:01:54.680001 NSTimerTest [1121:267663] link do nothing, linkCount = 31 2017-03-18 13:01:54.697108 NSTimerTest [1121:267663] link do nothing, linkCount = 32 2017-03-18 13:01:54.713726 NSTimerTest [1121:267663] link do nothing, linkCount = 33 2017-03-18 13:01:54.729956 NSTimerTest [1121:267663] link do nothing, linkCount = 34 2017-03-18 13:01:54.746658 NSTimerTest [1121:267663] link do nothing, linkCount = 35 2017-03-18 13:01:54.763778 NSTimerTest [1121:267663] link do nothing, linkCount = 36 2017-03-18 13:01:54.779953 NSTimerTest [1121:267663] link do nothing, linkCount = 37 2017-03-18 13:01:54.796732 NSTimerTest [1121:267663] link do nothing, linkCount = 38 2017-03-18 13:01:54.813729 NSTimerTest [1121:267663] link do nothing, linkCount = 39 2017-03-18 13:01:54.829980 NSTimerTest [1121:267663] link do nothing, linkCount = 40 2017-03-18 13:01:54.846751 NSTimerTest [1121:267663] link do nothing, linkCount = 41 2017-03-18 13:01:54.863757 NSTimerTest [1121:267663] link do nothing, linkCount = 42 2017-03-18 13:01:54.879957 NSTimerTest [1121:267663] link do nothing, linkCount = 43 2017-03-18 13:01:54.896619 NSTimerTest [1121:267663] link do nothing, linkCount = 44 2017-03-18 13:01:54.913648 NSTimerTest [1121:267663] link do nothing, linkCount = 45 2017-03-18 13:01:54.930006 NSTimerTest [1121:267663] link do nothing, linkCount = 46 2017-03-18 13:01:54.946953 NSTimerTest [1121:267663] link do nothing, linkCount = 47 2017-03-18 13:01:54.963751 NSTimerTest [1121:267663] link do nothing, linkCount = 48 2017-03-18 13:01:54.980065 NSTimerTest [1121:267663] link do nothing, linkCount = 49 |
3、总结
可以看出来,CADisplayLink“尽量”保证17ms执行一次,主要看NSRunloop中有没有执行其它事件时被阻塞
NSTimer的触发周期最小可以和NSRunloop的循环保持一致,也就是由NSRunloop的执行周期决定,大概2~3ms
因此这也是NSTimer也是不精确的原因
代码:https://github.com/liqiushui/NSRunloop
分类:
IOS开发问题积累
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架