1.CADisplayLink和NSTimer有什么区别?
- 原理不同:
CADisplayLink是一个能让我们以和屏幕刷新率同步的频率将特定的内容画到屏幕上的定时器类。 CADisplayLink以特定模式注册到runloop后, 每当屏幕显示内容刷新结束的时候,runloop就会向 CADisplayLink指定的target发送一次指定的selector消息, CADisplayLink类对应的selector就会被调用一次。
NSTimer以指定的模式注册到runloop后,每当设定的周期时间到达后,runloop会向指定的target发送一次指定的selector消息。
- 周期设置方式不同:
iOS设备的屏幕刷新频率(FPS)是60Hz,因此CADisplayLink的selector 默认调用周期是每秒60次,这个周期可以通过frameInterval属性设置, CADisplayLink的selector每秒调用次数=60/ frameInterval。比如当 frameInterval设为2,每秒调用就变成30次。因此, CADisplayLink 周期的设置方式略显不便。
NSTimer的selector调用周期可以在初始化时直接设定,相对就灵活的多。
- 精确度不同:
iOS设备的屏幕刷新频率是固定的,CADisplayLink在正常情况下会在每次刷新结束都被调用,精确度相当高。
NSTimer的精确度就显得低了点,比如NSTimer的触发时间到的时候,runloop如果在阻塞状态,触发时间就会推迟到下一个runloop周期。并且 NSTimer新增了tolerance属性,让用户可以设置可以容忍的触发的时间的延迟范围。
- 使用场景:
CADisplayLink使用场合相对专一,适合做UI的不停重绘,比如自定义动画引擎或者视频播放的渲染。
NSTimer的使用范围要广泛的多,各种需要单次或者循环定时处理的任务都可以使用。
2.CADisplayLink和NSTimer如何使用?
- CADisplayLink:
//定义属性
var displayLink: CADisplayLink?
//添加displayLink
func addDisplayLink() {
self.displayLink = CADisplayLink.init(target: self, selector: #selector(displayLinkAction))
self.displayLink?.add(to: RunLoop.main, forMode: .defaultRunLoopMode)
}
//销毁displayLink
func removeDisplayLink() {
self.displayLink?.invalidate()
self.displayLink = nil
}
//selector方法
@objc func displayLinkAction() {
//需要做的操作
}
- NSTimer:
//定义属性
var timer:Timer?
//添加timer
func addTimer1() {//使用scheduledTimer方法创建timer,会自动把timer加入MainRunloop的NSDefaultRunLoopMode中
self.timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
}
func addTimer2() {//使用init方法,需要手动将timer加入MainRunloop的NSDefaultRunLoopMode中
self.timer = Timer.init(timeInterval: 1.0, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
RunLoop.main.add(self.timer, forMode: .defaultRunLoopMode)
}
//销毁timer
func removeTimer() {
self.timer?.invalidate()
self.timer = nil
}
//selector方法
@objc func timerAction() {
//需要做的操作
}
- 注释:
通常我们使用NSTimer的时候都是在主线程使用的,主线程负责很多复杂的操作,例如UI处理,UI时间响应,并且iOS上的主线程是优先响应UI事件的,而NSTimer的优先级较低,有时候NSTimer的触发并不准确,例如当我们在滑动UIScrollView的时候,NSTimer就会延迟触发,主线优先响应UI的操作,只有UIScrollView停止了才触发NSTimer的事件
--解决方案 --
NSTimer加入到runloop默认的Mode为NSDefaultRunLoopMode, 我们需要手动设置Mode为NSRunLoopCommonModes
这时候,NSTimer即使在UI持续操作过程中也能得到触发,当然,会降低流畅度
网友评论