更新时间:2022-04-09 21:48:17
这是一个一个简单的示例,展示了我将如何实现 CADisplayLink
(在Swift 3中):
Here’s a simple example showing how I’d go about implementing a CADisplayLink
(in Swift 3):
class C { // your view class or whatever
private var displayLink: CADisplayLink?
private var startTime = 0.0
private let animLength = 5.0
func startDisplayLink() {
stopDisplayLink() // make sure to stop a previous running display link
startTime = CACurrentMediaTime() // reset start time
// create displayLink & add it to the run-loop
let displayLink = CADisplayLink(
target: self, selector: #selector(displayLinkDidFire)
)
displayLink.add(to: .main, forMode: .commonModes)
self.displayLink = displayLink
}
@objc func displayLinkDidFire(_ displayLink: CADisplayLink) {
var elapsed = CACurrentMediaTime() - startTime
if elapsed > animLength {
stopDisplayLink()
elapsed = animLength // clamp the elapsed time to the anim length
}
// do your animation logic here
}
// invalidate display link if it's non-nil, then set to nil
func stopDisplayLink() {
displayLink?.invalidate()
displayLink = nil
}
}
注意事项:
nil
来表示显示链接未运行的状态– removeFromRunLoop()
,而是使用 invalidate()
,如果尚未将显示链接添加到运行循环中,则不会崩溃。但是,这种情况永远都不会出现-因为我们总是在创建显示链接后立即将其添加到运行循环中。 displayLink
私有,以防止外部类将其置于意外状态(例如,使其无效但不将其设置为 stopDisplayLink()
方法,该方法会使显示链接无效(如果它不是nil)并将其设置为 nil
–而不是复制并粘贴此逻辑。已暂停
更改为 true
,然后取消显示链接,因为这是多余的。 displayLink
检查是否为非零后,我们使用可选的链接,例如 displayLink?.invalidate()
(将称为 invalidate()
(如果显示链接不是nil)。尽管在您给定的情况下(当您检查是否为零时)强制展开可能是安全的 –在将来的重构中它可能是不安全的,因为您可以在不考虑这对强制展开产生什么影响的情况下重新构造逻辑。已花费
的时间限制为动画持续时间,以确保以后的动画逻辑不会产生值超出预期范围。 displayLinkDidFire(_:)
接受单个类型为 CADisplayLink
,根据文档需要 。nil
here to represent the state in which the display link isn’t running – as there’s no easy way of getting this information from an invalidated display link.removeFromRunLoop()
, we’re using invalidate()
, which will not crash if the display link hasn’t already been added to a run-loop. However this situation should never arise in the first place – as we’re always immediately adding the display link to the run-loop after creating it.displayLink
private in order to prevent outside classes from putting it in an unexpected state (e.g invalidating it but not setting it to nil
).stopDisplayLink()
method that both invalidates the display link (if it is non-nil) and sets it to nil
– rather than copy and pasting this logic.paused
to true
before invalidating the display link, as this is redundant.displayLink
after checking for non-nil, we’re using optional chaining e.g displayLink?.invalidate()
(which will call invalidate()
if the display link isn’t nil). While force unwrapping may be ‘safe’ in your given situation (as you’re checking for nil) – it’s potentially unsafe when it comes to future refactoring, as you may re-structure your logic without considering what impact this has on the force unwraps.elapsed
time to the animation duration in order to ensure that the later animation logic doesn’t produce a value out of the expected range.displayLinkDidFire(_:)
takes a single argument of type CADisplayLink
, as required by the documentation.