[英]Definitively, do you have to invalidate() a CADisplayLink when the controller disappears?
Say you have an everyday CADisplayLink
假设你有一个日常的
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)
}
Eventually the view controller is dismissed. 最终视图控制器被解雇。
Does anyone really definitively know, 有谁真的知道,
do you have to explicitly call .invalidate()
(and indeed nil _ca) when the view controller is dismissed? 当视图控制器被解除时,你是否必须显式调用
.invalidate()
(实际上是nil _ca)?
(So perhaps in deinit, or viewWillDisappear, or whatever you prefer.) (所以也许在deinit,或者viewWillDisappear,或者你喜欢的任何东西。)
The documentation is worthless, and I'm not smart enough to be able to look in to the source. 文档毫无价值,我不够聪明,无法查看源代码。 I've never found anyone who truly, definitively, knows the answer to this question.
我从未发现任何真正明确地知道这个问题答案的人。
Do you have to explicitly invalidate, will it be retained and keep running if the VC goes away? 如果VC消失,你是否必须明确地使其无效,是否会被保留并继续运行?
A run loop keeps strong references to any display links that are added to it. 运行循环保持对添加到其中的任何显示链接的强引用。 See
add(to:forMode:)
documentation: 请参阅
add(to:forMode:)
文档:
The run loop retains the display link.
运行循环保留显示链接。 To remove the display link from all run loops, send an
invalidate()
message to the display link.要从所有运行循环中删除显示链接,请向显示链接发送
invalidate()
消息。
And a display link keeps strong reference to its target
. 并且显示链接保持对其
target
强引用。 See invalidate()
documentation: 请参见
invalidate()
文档:
Removing the display link from all run loop modes causes it to be released by the run loop.
从所有运行循环模式中删除显示链接会导致它被运行循环释放。 The display link also releases the target.
显示链接也会释放目标。
So, you definitely have to invalidate()
. 所以,你肯定
invalidate()
。 And if you're using self
as the target
of the display link, you cannot do this in deinit
(because the CADisplayLink
keeps a strong reference to its target). 如果您使用
self
作为显示链接的target
,则无法在deinit
执行此deinit
(因为CADisplayLink
保留了对其目标的强引用)。
A common pattern if doing this within a view controller is to set up the display link in viewDidAppear
and remove it in viewDidDisappear
. 如果在视图控制器中执行此操作,则常见的模式是在
viewDidAppear
设置显示链接并在viewDidDisappear
中将其删除。
For example: 例如:
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
}
Method definition of invalidate() : invalidate()的方法定义:
Removing the display link from all run loop modes causes it to be released by the run loop.
从所有运行循环模式中删除显示链接会导致它被运行循环释放。 The display link also releases the target.
显示链接也会释放目标。
For me this means that displaylink holds the target and run loop holds DispayLink. 对我来说,这意味着displaylink保持目标并且运行循环保持DispayLink。
Also, according to this link I found, it looks like its rather important to call invalidate() for cleanup of CADisplayLink
. 另外,根据我发现的这个链接 ,调用invalidate()来清理
CADisplayLink
看起来非常重要。
We can actually validate using XCode's wonderful Memory graph debugger : 我们实际上可以使用XCode的精彩内存图调试器进行验证:
I have created a test project where a DetailViewController
is being pushed on a navigation stack. 我创建了一个测试项目,其中一个
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)
}
}
This initiates CADispalyLink
when view gets appeared. 当视图出现时,这将启动
CADispalyLink
。
If we check the memory graph, we can see that DetailViewController
is still in the memory and CADisplayLink
holds its reference. 如果我们检查内存图,我们可以看到
DetailViewController
仍然在内存中,而CADisplayLink
保存它的引用。 Also, the DetailViewController
holds the reference to CADisplayLink
. 此外,
DetailViewController
保存对CADisplayLink
的引用。
If we now call invalidate()
on viewDidDisappear()
and check the memory graph again, we can see that the DetailViewController
has been deallocated successfully. 如果我们现在在
viewDidDisappear()
invalidate()
上调用invalidate()
并再次检查内存图,我们可以看到DetailViewController
已成功释放。
This to me suggests that invalidate is a very important method in CADisplayLink and should be called to dealloc CADisplayLink to prevent retain cycles and memory leaks. 这对我来说,无效是CADisplayLink中一个非常重要的方法,应该调用dealloc CADisplayLink以防止保留周期和内存泄漏。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.