[英]Definitively, do you have to invalidate() a CADisplayLink when the controller disappears?
假设你有一个日常的CADisplayLink
class Test: UIViewController {
private var _ca : CADisplayLink?
@IBAction func frames() {
_ca?.invalidate()
_ca = nil
_ca = CADisplayLink(
target: self,
selector: #selector(_step))
_ca?.add(to: .main, forMode: .commonModes)
}
@objc func _step() {
let s = Date().timeIntervalSince1970
someAnime.seconds = CGFloat(s)
}
最终视图控制器被解雇。
有谁真的知道,
当视图控制器被解除时,你是否必须显式调用.invalidate()
(实际上是nil _ca)?
(所以也许在deinit,或者viewWillDisappear,或者你喜欢的任何东西。)
文档毫无价值,我不够聪明,无法查看源代码。 我从未发现任何真正明确地知道这个问题答案的人。
如果VC消失,你是否必须明确地使其无效,是否会被保留并继续运行?
运行循环保持对添加到其中的任何显示链接的强引用。 请参阅add(to:forMode:)
文档:
运行循环保留显示链接。 要从所有运行循环中删除显示链接,请向显示链接发送
invalidate()
消息。
并且显示链接保持对其target
强引用。 请参见invalidate()
文档:
从所有运行循环模式中删除显示链接会导致它被运行循环释放。 显示链接也会释放目标。
所以,你肯定invalidate()
。 如果您使用self
作为显示链接的target
,则无法在deinit
执行此deinit
(因为CADisplayLink
保留了对其目标的强引用)。
如果在视图控制器中执行此操作,则常见的模式是在viewDidAppear
设置显示链接并在viewDidDisappear
中将其删除。
例如:
private weak var displayLink: CADisplayLink?
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
startDisplayLink()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
stopDisplayLink()
}
private func startDisplayLink() {
stopDisplayLink() // stop previous display link if one happens to be running
let link = CADisplayLink(target: self, selector: #selector(handle(displayLink:)))
link.add(to: .main, forMode: .commonModes)
displayLink = link
}
private func stopDisplayLink() {
displayLink?.invalidate()
}
@objc func handle(displayLink: CADisplayLink) {
// do something
}
invalidate()的方法定义:
从所有运行循环模式中删除显示链接会导致它被运行循环释放。 显示链接也会释放目标。
对我来说,这意味着displaylink保持目标并且运行循环保持DispayLink。
另外,根据我发现的这个链接 ,调用invalidate()来清理CADisplayLink
看起来非常重要。
我们实际上可以使用XCode的精彩内存图调试器进行验证:
我创建了一个测试项目,其中一个DetailViewController
被推送到导航堆栈上。
class DetailViewController: UIViewController {
private var displayLink : CADisplayLink?
override func viewDidAppear() {
super.viewDidAppear()
startDisplayLink()
}
func startDisplayLink() {
startTime = CACurrentMediaTime()
displayLink = CADisplayLink(target: self,
selector: #selector(displayLinkDidFire))
displayLink?.add(to: .main, forMode: .commonModes)
}
}
当视图出现时,这将启动CADispalyLink
。
如果我们检查内存图,我们可以看到DetailViewController
仍然在内存中,而CADisplayLink
保存它的引用。 此外, DetailViewController
保存对CADisplayLink
的引用。
如果我们现在在viewDidDisappear()
invalidate()
上调用invalidate()
并再次检查内存图,我们可以看到DetailViewController
已成功释放。
这对我来说,无效是CADisplayLink中一个非常重要的方法,应该调用dealloc CADisplayLink以防止保留周期和内存泄漏。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.