简体   繁体   English

确切地说,当控制器消失时,你是否必须使()CADisplayLink无效?

[英]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.

相关问题 如何使用 UIButton 使 CADisplayLink 无效? - How do I invalidate CADisplayLink with a UIButton? 在弹出过渡到的视图控制器之前,如何使单元格保持突出显示状态? - How do you have a cell stay highlighted until you pop the view controller it transitions to? 什么时候需要为控制器创建一个单独的xib? - When do you need to create a seperate xib for your controller? 从存档构建时,CADisplayLink会断断续续 - CADisplayLink stutters when built from archive (iphone)重复时我需要使计时器无效:不是吗? - (iphone) do I need to invalidate timer when repeats: no? CADisplayLink因为remove(from:forMode :)而不是取消分配视图控制器 - CADisplayLink because of remove(from:forMode:) not deallocating view controller 按下视图控制器时,UINavigationItem的标题消失 - UINavigationItem's title disappears when view controller is pushed 如何防止NSFetchedResultsController在控制器消失时更新tableview? - How to prevent NSFetchedResultsController from updating tableview when the controller disappears? 更改视图控制器时,会出现新的控制器,但几乎立即消失 - When changing view controllers, new controller appears, but disappears almost immediately 从模态视图控制器返回时,标签栏消失 - Tab bar disappears when returning from modal view controller
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM