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

w3nuxt5m  于 2022-12-10  发布在  Swift
关注(0)|答案(7)|浏览(178)
UIView.animateWithDuration(1,
        animations: { [unowned self] in
            self.box.center = self.boxTopRightPosition
        },
        completion: { [unowned self] completed in
            self.box.hidden = true
    })

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

8yparm6h

8yparm6h1#

不,在这种情况下不需要。animationscompletion不被self保留,因此不存在强保留周期的风险。

fcy6dtqo

fcy6dtqo2#

当然,“必要”和“推荐”是不一样的。如果你的问题是“是否有必要”,那么@Kirsteins的回答很好,但是想象一下这样的情况:你想在完成一些工作后在视图控制器中制作动画,但是视图控制器已经被释放了(因为它不再处于视图层次结构中或任何其他原因).在这种情况下,如果不使用[weak self],视图控制器在动画完成之前不会被释放,因为您将其保留在动画块中,但在动画化视图中不再存在的内容之前保留它是否有意义?
因此,简而言之,在制作UIKit动画时,您不 * 需要 * 使用weak引用self,但是,如果发布了视图,您不需要保留视图,因为没有视图的动画没有意义,因此使用weak是一个很好的选择。

x4shl7ld

x4shl7ld3#

不需要。正如Kirsteins所说:
不,在这种情况下不需要。动画和完成不是由自己保留的,所以没有强保留周期的风险。
但是lhmgrassi说:
一旦它被解除分配,解除初始化程序将被调用,完成将永远不会被执行。
我不认为这是真的。完成块总是会被调用。如果你使用一个强self,你的对象在完成块被执行之前不会被释放。
然而,如果你使用[weak self],你的对象不会(临时)被完成块保留,并且可能在完成块被激发之前被释放。完成块仍然被激发,但是self已经是nil
如果在完成处理程序中使用[unowned self],则对象也可能在调用完成处理程序之前被释放,这可能会导致崩溃!
我举了一个例子来说明这一点。

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

f2uvfpb9

f2uvfpb94#

@Plabo,正如@Kirsteins所说,动画和补全并不是由self保留的,所以即使你启动了一个动画,而你的视图控制器由于某种原因被释放了,它也会立即被释放。所以,你不需要捕获“self”。考虑下面这个愚蠢的例子:

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

}

一旦它被解除分配,解除初始化程序将被调用,完成将永远不会被执行。

siotufzp

siotufzp5#

正好相反,你 * 希望 * self继续存在足够长的时间,以便完成块被调用。因此,让self很强,并通过转义完成处理程序保留下来是一件 * 好事 *。
通常人们使用weak self的担心是一个保留 * 循环 *。但这不是。保留循环是当self保留闭包时,闭包保留self,导致泄漏,因为self永远不能被释放。但这根本不是那种情况。闭包,因此self,被保留了。但不是由self!所以有一些保留正在进行,暂时的,但它是 * 好 *,不坏。

bq3bfh9z

bq3bfh9z6#

不需要在动画、GCD或完成处理程序中使用弱/无主,因为:
它们捕获的外部对象引用将只保留固定时间***,这意味着它将在一个时间点被确定执行。在此之后,它将被释放,因此不存在导致内存泄漏的引用循环的机会。
如前面的答复所示,
如果
动画完成不是自己保留的,那么谁保留它们?
我没有找到任何书面证据,但我相信
它们被自我保留了一段固定的时间***。在这之后,完成执行并释放自我,这导致了自我的解除分配。
在保留循环场景中,闭包被self和self被闭包保留不确定的时间,这被认为是引用循环和内存泄漏。

mccptt67

mccptt677#

在这个问题上有许多错误的答案。weak self从来不需要动画。
一旦你在ViewController上调用dismiss,动画完成将被调用(成功为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秒后

相关问题