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

Wil*_*Cat 35 memory closures ios swift

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

是否有必要避免内存泄漏?

Kir*_*ins 50

不,在这种情况下不需要.animations并且completion不会被保留,self因此不存在强保留周期的风险.

  • 是否在某个地方记录了该块因此无法自行保留的情况? (4认同)
  • 如果self保留了对UIView的强烈引用,闭包不是由self间接保留的吗? (2认同)

Pab*_* A. 30

嗯,"必要"与"推荐"不一样.如果您的问题是否有必要,那么@Kirsteins的回答很好,但是想象一下你想在一些工作之后在视图控制器中制作动画的情况,但你的视图控制器已经被释放(因为它不再在视图层次结构中了)或任何其他原因).在这种情况下,如果你不使用[weak self],你的视图控制器将在完成动画之前不会被释放,因为你将它保留在动画块中,但是保持它是有意义的是保持它直到动画不在再看一次?

所以,简单来说,在动画UIKit时你不需要使用weak自我引用,但是,如果它被释放你不需要保留你的视图,因为没有视图的动画没有意义,所以使用weak是一个不错的选择.

  • 不错,正确。不明白为什么这个答案不是最重要的:) (2认同)
  • 正确。长话短说,在dispatchQueues / animation块中使用`[weak self]`或`[unown self]`只是“控制流的手段”。这与内存无关。_最终_他们将执行/完成并释放对象(取决于可能在2或10或200秒内完成的块)。有关更多信息,请参阅[如何使用dispatchQueues创建参考周期?](/sf/ask/3924276471/) (2认同)

Tie*_*eme 13

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

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

但是lhmgrassi说:

一旦取消分配,将调用反初始化程序,并且永远不会执行完成。

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

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

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

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

[gif说明问题

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


小智 6

@Plabo,正如@Kirsteins所说,动画和完成不会被自己保留,所以即使你开始动画并且出于任何原因你的视图控制器已经被释放,它也会立即释放出来.所以,你不需要捕获'自我'.考虑以下愚蠢的例子:

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")
    }

}
Run Code Online (Sandbox Code Playgroud)

一旦取消分配,将调用deinitializer并且永远不会执行完成.


mat*_*att 6

恰好相反。您希望 self继续存在足够长的时间以便调用完成块。因此,self通过转义完成处理程序保持强大和保留是一件好事

通常导致人们使用的担心weak self是保留周期。但这不是那样。保留周期是指当self保留保留的闭包时self,会导致泄漏,因为现在self永远无法释放。但这根本不是那样的情况。闭包因此self被保留,但不是被self! 所以暂时会有一些保留,但这是好的,而不是坏的。