UIView.animate():在动画块中是否需要对self使用weak引用?

9

经过一些研究,我发现我的应用程序因为整个应用程序中有多个 UIView 动画,而且在完成块中捕获了相关的 UIViewController 而没有进行弱引用,因此使用了过多的能量。

实际上,我对此进行了更改:

func animate() {
    UIView.animate(withDuration: 0.3, animations: {
        self.label.alpha = 0.5
    }) { _ in 
        self.animate()
    }
}

转化为:

func animate() {
    UIView.animate(withDuration: 0.3, animations: {
        self.label.alpha = 0.5
    }) { [weak self] _ in 
        self?.animate()
    }
}

但是,我想知道是否需要对animation块(指self.label.alpha = 0.5的部分)执行相同的操作?

感谢您的帮助。


1
这里的答案是误导性的。请参见此处 - mfaani
4个回答

6

5
你不需要在UIView.animate()中使用[weak self]。当可能存在保留循环且动画块未被self保留时,需要使用weak。
Medium上有一篇关于何时需要使用[weak self]文章
更多信息:
- 自动引用计数 - 闭包 能源问题可能还有其他问题。

这不是关于“静态”的问题,而是关于所有权的问题。请参见此处 - mfaani

0

什么是:

我的应用程序使用了太多的能量

我没有看到在您的视图控制器上保持weak引用和节省能源之间的直接关系。 在闭包中捕获self而不增加其保留计数(这就是我们所说的在对象上具有弱引用的含义)意味着如果不存在对您的视图控制器的其他强引用,则您的视图控制器将更快地被释放。也许您会在短期内节省一些RAM。

我建议您在其他地方调查以找出您的“能源”问题来自何处。

有很多关于使用weak关键字的文章。

https://medium.com/flawless-app-stories/you-dont-always-need-weak-self-a778bec505ef


嗨,Lucien - 这非常明显。因为 OP 忘记了 weak self,他将会不断地建立更多的视图控制器。可能会有数百个这样的控制器。 - Fattie

-4
当然,你确实需要在那里使用“弱引用self”的概念。
事实上请注意:在动画过程中,VC通常会被清除...因此,在这种情况下,“最需要”使用弱引用self的地方之一。在项目中忘记在动画中使用它是一个非常常见的错误。
顺便说一下,在任何时候需要使用弱引用self的情况下,以下是一个方便的语法:
func animate() {
    UIView.animate(withDuration: 0.3, animations: { [weak self] in
        guard let self = self else { return print("gotchya!") }
        self.label.alpha = 0.5
    }) { [weak self] in
        guard let self = self else { return print("gotchya!") }
        self.animate()
    }
}

添加这行代码...

        guard let self = self else { return }

.. 可能看起来有点冗长,但这意味着在长块中每次使用 "self" 时就不需要再加上 "?"。

通常你会在这样的块内有许多使用 "self ..." 的情况,使用 "let self = self" 的习惯似乎更加一致。

enter image description here

因此,即使代码块中只有一行代码(就像您的两个示例中一样),这也是确保在任何地方都绝对一致并保持简单的好方法。

请注意,每当您有一个{ return }时,您可以添加一个打印语句,以便在开发过程中了解正在发生的情况..

.... { [weak self] in
  guard let self = self else { return print("I avoided a crash, woot!") }

或者

.... { [weak self] in
  guard let self = self else { return print("logical disaster near line 66") }

你不必这样做,"{ return }" 就可以了。这只是为了方便你。

这个 "self = self" 是什么鬼?

如果你觉得 "self = self" 这个习惯用法很困惑......老实说,别担心它。总是使用这个习惯用法。这真的只是你到处都会看到的 "标准" 东西。

在你的代码库中始终保持简单的一致性!

更多关于 weak self 的奥秘......

这里有一个来自一个英俊的列表成员的有趣问答:weak self 去哪里了?

后来还有这种困惑要担心:弱引用和无主引用之间有什么区别?


2
这个答案目前被接受有点令人困惑。据我理解,在这种情况下不需要使用weak self来防止保留循环,这也是最初的问题所在。但是它可以作为控制流的手段来使用。 - hoshy
我明白你的意思@hoshy,正如我在答案或这里https://dev59.com/w18d5IYBdhLWcg3wRAaE#39251222中所解释的那样,你需要“在实践中”使用它,因为你永远不想在动画播放时保留一个消失的视图。这么说吧-在你所在的任何团队上工作,如果你忘记了它,团队负责人会将其添加到提交中:)这是你“必须做的事情”。 - Fattie
1
顺便问一下,你有没有任何参考指南证实 guard let self = self else { return } 比在闭包内使用 self?. 更好?在 PR 过程中,我和同事争论了这个问题。我的观点是,如果没有 self 了,最好立即离开闭包,而不是在其中执行随机的逻辑片段,但我想要一些额外的佐料 :) - nrx
12
这个答案实际上是错误的!首先,animations闭包将立即运行,并且不会在动画期间存储。我猜测UIKit会运行它来确定最终状态,然后将其丢弃。其次,“completion”闭包将在“VC在动画期间被垃圾回收”时立即调用,并且“finished”参数将是false。因此,这两个闭包都不需要使用[weak self]。另外,如果您想在“completion”中使用[weak self]以“如果VC被垃圾回收则不运行代码”,则可以使用!finished - Lord Zsolt
@LordZsolt 你好,Lord! :) 当然,这是一个经常讨论的问题。我基本上同意这个答案:https://dev59.com/w18d5IYBdhLWcg3wRAaE#39251222 (文本开始于“Well, "necessary" isn't the same as "recommended"...”) - Fattie
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接