繁体   English   中英

是否有必要在 UIView.animateWithDuration(...) 的闭包中使用 [unowned self]?

[英]Is it necessary to use [unowned self] in closures of UIView.animateWithDuration(...)?

    UIView.animateWithDuration(1,
        animations: { [unowned self] in
            self.box.center = self.boxTopRightPosition
        },
        completion: { [unowned self] completed in
            self.box.hidden = true
    })

是否有必要避免 memory 泄漏?

不,在这种情况下不需要。 animationscompletion不被保留self ,所以没有强烈的保留周期的风险。

好吧,“必需”与“推荐”不同。 如果您的问题是是否有必要,那么@Kirsteins的响应很好,但是请设想一下您想在完成一些工作后在视图控制器中对某些东西进行动画处理,但视图控制器已被释放的情况(因为它不再在视图层次结构中了)或任何其他原因)。 在这种情况下,如果您不使用[weak self] ,则在完成动画之前不会释放视图控制器,因为您将其保留在动画块中,但是将其保留直到动画化某些东西才有意义不在视野中了吗?

因此,简而言之,在对UIKit进行动画处理时, 不需要使用对自身的weak引用,但是,如果发布了视图,则无需保留视图,因为没有视图的动画是没有意义的,因此使用weak是一个不错的选择。

不,不需要。 正如柯斯坦斯所说:

不,在这种情况下不需要。 动画和完成不是自己保留的,因此没有强大的保留周期的风险。

但是lhmgrassi说:

一旦解除分配,将调用反初始化器,并且永远不会执行完成。

我不认为这是真的。 完成模块将始终被调用。 而且,如果您使用强大的自我,则在执行完成块之前,不会释放对象。

但是,如果使用[weak self] ,则完成块不会(临时)保留您的对象,并且可能在激发完成块之前将其释放。 完成块仍被触发,但self已为nil

如果在完成处理程序中使用[unowned self] ,则在完成处理程序被调用之前,对象也可能会被释放,这可能导致崩溃!

我已经举例说明了这一点。

[gif说明问题

完整的源代码可以在Github找到

正如@Kirsteins所说,@ Plabo不会自行保留动画和完成,因此,即使您开始动画并且由于某种原因释放了视图控制器,它也会立即释放。 因此,您不需要捕获的“自我”。 考虑下面这个愚蠢的例子:

class ViewController: UIViewController {

    @IBOutlet weak var button : UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        print("viewDidLoad ViewController")
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        UIView.animate(withDuration: 20, animations: {
            self.button.frame = CGRect(x: 0, y: 300, width: 30, height: 30)
        }) { finished in
            self.button.frame = CGRect(x: 0, y: 100, width: 30, height: 30)
        }
    }

    deinit {
        print("deinit ViewController")
    }

}

一旦解除分配,将调用反初始化器,并且永远不会执行完成。

恰好相反。 希望 self继续存在足够长的时间,以便调用完成块。 因此具有self坚强,通过退避完成处理保留是一件好事

通常导致人们使用weak self的烦恼是一个保留周期 但这不是那样。 一个保留周期时, self保留保留了封闭self ,造成泄漏,因为现在self可以永远不会被释放。 但这根本不是那种情况。 封闭,因此self ,被保留,而不是self保留! 因此,暂时会有一些保留,但这很好 ,还不错。

不需要在Animations,GCD或完成处理程序中使用弱/无用的因为:

它们捕获的外部对象引用将仅保留固定的时间 ,这意味着它将在某个时间点执行。 此后,它将被释放,因此不会有导致内存泄漏的参考周期机会。

如先前的答案所示,

如果动画完成不是自己保留的,那么谁保留它们?

我没有找到任何书面证据,但我相信它们是自己保留的,但是固定的时间里 此后,完成执行并释放自我,这导致自我的取消分配。

在保留周期方案中,闭包将由self和self由闭包保留不确定的时间,这被视为参考周期和内存泄漏。

关于这个问题的许多错误答案。 动画永远不需要weak self

一旦您在 ViewController 上调用dismiss ,将调用 animation 完成(成功为 false),并且您的 ViewController 将被释放,即使有很强的自引用也是如此。

通过这个测试:

class TestVC: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .blue

        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            self.view.alpha = 1
            UIView.animate({
                self.view.alpha = 0
            }, duration: 40) { success in
                print("finished: \(success)")
                self.view.backgroundColor = .green
            }
        }

        DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
            self.dismiss(animated: true)
        }
    }

    deinit {
        print("deinit")
    }
}

在日志中,您将获得:

finished: false
deinit

6 秒后

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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