繁体   English   中英

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

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM