一、在实际开发中的应用
- 控制线程生命周期(线程保活)
- 解决NSTimer在滑动时停止工作的问题
- 监控应用卡顿
- 性能优化
二、控制线程生命周期(线程保活)
在项目中会遇到创建一个子线程去做一些事情。为什么要创建一个子线程去做事情?因为如果把所有的事情都放在主线程中去做,就会阻塞住组线程。导致APP 看起来很卡。这个时候就可以开启一个子线程,把耗时的操作放到子线程中。这样就不会阻塞主线程,APP 开起来不会卡。
子线程做完事情以后,就会销毁。但有的时候,希望子线程昨晚事情以后,不要销毁,当程序员需要的时候才销毁。这个时候就可以使用 RunLoop 控制子线程的生命周期。
这种做法也叫做线程保活(保住线程的命)。
三、解决NSTimer在滑动时停止工作的问题
(一)、为什么 NSTimer 不能再滚动 UIScrollView时保持开启状态
-
默认情况下,在滚动 tableView、UIScrollView 的时候。NSTimer会停止工作。
-
创建一个 UITextView, UITextView 是 UIScrollView 的子类。使用它来演示 NSTimer 在滑动时停止工作的问题
-
写一个 定时器代码,每隔一秒钟打印一次
-
当滚动 UITextView 的时候,定时器停止打印。这是因为 混动 UITextView 的时候,RunLoop 会进入另一个Mode 模式UITrackingRunLoopMode 下.
-
当在UITrackingRunLoopMode模式下,定时器会停止。
-
当不在滚动 UITextView , 定时器会重新开始。
-
这是因为 RunLoop 同一时间,只能运行一种模式。当滚动UITextView 的时候,定时器会停止。说明这两个模式不一样。也就是说 NSTimer 不是 UITrackingRunLoopMode 模式。
-
NSTimer 是在默认模式下工作的。kCFRunLoopDefaultMode模式
-
也可以使用
CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent())
打印一下当前的 模式
注:
- kCFRunLoopDefaultMode(NSDefaultRunLoopMode):App的默认Mode,通常主线程是在这个Mode下运行
- UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响
(二)、让 NSTimer 在 滚动 UIScrollView时也可以滚动
- 方法
[NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) { ... ... }];
会直接把定时器添加到 默认mode中 - 方法
[NSTimer timerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) { ... ... }];
只是返回一个 NSTimer 中。没有添加到 runloop 中. [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
把 timer 添加到 runloop 中。 forMode 后面可以添加三种:- NSDefaultRunLoopMode : 默认模式
- UITrackingRunLoopModes: UIScrollView 的那种模式
- NSRunLoopCommonModes: 通用模式 。
- 它并不是一个真的模式,它只是一个标记
- 上面的 NSDefaultRunLoopMode 和 UITrackingRunLoopModes 才是 真正存在的模式
- 传入这个 ,意味着:timer 在设置了 common 标记的模式下都能运行。而 NSDefaultRunLoopMode 和 UITrackingRunLoopModes 都标记成了 Common 。 所以在这两个mode 上都可以使用。
(三)、回顾 RunLoop 的定义
-
RunLoop 的结构
- 线程(pthread_t _pthread): 一个 RunLoop 有一个线程 。 一对一。
- 模式(CFMutableSetRef _modes): 里面装着 RunLoop 能用的模式. 有很多个
- 当前模式(CFRunLoopModeRef _currentMode)
- CFMutableSetRef _commonModes: 装到这里的模式,意味着标记成了 common 的模式。
- CFMutableSetRef _commonModeItems: 存放能在_commonModes 下工作的 东西(如刚才的 timer 变量)
-
当调用
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonMode];
代码时,它调用的就是 runloop 中的 CFMutableSetRef _commonModes.。 -
这个common模式下包含 NSDefaultRunLoopMode 和 UITrackingRunLoopModes 这两个模式。
-
所以 timer 能在 _commonModes 数组中存放的模式下工作。
四、监控应用卡顿
五、性能优化