【问题标题】:Swift Memory management when pass a closure as parameter to singleton将闭包作为参数传递给单例时的 Swift 内存管理
【发布时间】:2017-05-19 21:36:24
【问题描述】:

我知道closure 可以创建retain cycles,如果它被分配给一个类的属性并且类的实例属性在闭包内部使用。但是

1) 闭包没有分配给类属性而是作为参数传递给单例的类方法怎么办?

2) 这种情况下内存是如何管理的?

在我的控制器 (UIViewController) 的方法中,我有类似的东西:

MySingleton.classMethod(parameters ..., completion: { () -> Void in
   /**
   doing stuff here
   */
})

【问题讨论】:

    标签: ios swift memory-management singleton retain-cycle


    【解决方案1】:

    如果您没有将闭包分配给属性,而只是将其传递给函数您需要考虑闭包是转义还是不转义。默认情况下,在 Swift 3 中,所有传递给函数的闭包都是非转义的。

    这里是关于此事的更多信息:

    "noescape" - 在函数返回之前调用传递的闭包

    "escaping" - 如果闭包作为参数传递给函数并在函数返回后调用,则闭包正在转义。

    简单解释:我们需要在传递给函数的时候将闭包标记为转义,这个函数返回后会调用闭包。

    一般规则是当闭包转义时您需要使用捕获列表来防止保留循环。

    例子

    let closure = { [weak someVariable] (name: Type) -> Void in
    ....
    // code
    }
    

    附加信息:

    一个奇怪的事情是可选闭包被视为转义。而当我们显式添加转义关键字时,会有一个编译错误——转义属性只适用于函数类型。

    查看以下链接了解更多信息。

    https://bugs.swift.org/browse/SR-2053

    https://stackoverflow.com/a/39619298/5388473

    https://stackoverflow.com/a/39846519/5388473

    更新
    在转义闭包的捕获列表中使用弱或无主的想法是,本质上我们不知道传递的转义闭包会发生什么,它可能稍后从另一个函数调用,或者它可能存储在某个对象中,这可能会导致强大的保留周期。

    弱vs无主vs强捕获

    更多详细信息请查看Apple ARC docs

    来自 Apple 文档:

    Swift 提供了两种解决强引用循环的方法: 使用类类型的属性:弱引用和无主 参考文献。

    弱引用和无主引用在引用周期中启用一个实例 引用另一个实例而不牢牢抓住它。 然后实例可以相互引用而不创建强 参考循环。

    当另一个实例的引用较短时使用弱引用 生命周期——也就是说,当另一个实例可以首先被释放时。 当另一个实例具有相同的生命周期时,使用无主引用 或更长的使用寿命。

    请记住,weak 方法会在代码中添加样板并且会稍微慢一些,因为 ARC 会添加代码以在释放时将弱变量设置为 nil。在选择弱或无主时,遵循上述规则是一种很好的做法。

    【讨论】:

    • 如果 self 是对单例的引用,那么在此处使用 weak 并不是绝对必要的(尽管可能仍然是好的做法),因为单例永远不会被释放,因此在闭包中对它的强引用不会'没关系。只要有对它的引用,该块仍将存在。另一方面,如果 self 引用一个外部类(不是单例),并且使用了 weak,那么外部类会根据 arc 的通常规则被释放。如果 self 不弱,则该类将被保留,直到块被释放。
    • 对不起self只是一个例子,我将它重命名为someVariable。
    • 用更多关于可选闭包编译错误的信息更新了答案。
    • 您能否解释一下为什么“...当闭包转义时,您需要使用捕获列表来防止保留循环。”。
    • 查看这个答案,它非常彻底。 stackoverflow.com/a/24320474/5388473
    猜你喜欢
    • 2022-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-09
    • 2015-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多