Swift Struct内存泄漏

时间:2015-12-21 23:37:15

标签: swift memory-leaks rx-swift

我们正试图尽可能使用Swift结构。我们也在使用RxSwift,它具有关闭的方法。当我们有一个结构创建一个引用 self 的闭包时,它会创建一个strong reference cycle

import Foundation
import RxSwift

struct DoesItLeak {

    var someState: String = "initial value"
    var someVariable: Variable<String> = Variable("some stuff")

    let bag = DisposeBag()

    mutating func someFoo() {

        someVariable.subscribeNext { person in

            self.someState = "something"
        }
        .addDisposableTo(bag)
    }
}

我怎么知道这个?如果我创建100,000个DoesItLeak对象并在每个对象上调用someFoo(),我相信我有100,000个具有强引用周期的对象。换句话说,当我摆脱包含这些对象的DoesItLeak数组时,对象会留在内存中。如果我不调用someFoo(),则没有问题。

变量是一个类。所以,我可以通过使用xcode的仪器分配和变量&lt;中的过滤来看到这个内存问题。字符串&gt;

Filtering By Variable

enter image description here

如果我尝试使用[弱自我],如下所示,我收到编译错误:

someVariable.subscribeNext { [weak self] person in

编译错误是“弱不能应用于非类型”

在真实/非示例代码中,我们通过self访问方法和变量,这是一个内存问题。

如何在保持DoesItLeak结构的同时解决此内存问题?

感谢您的帮助。

4 个答案:

答案 0 :(得分:6)

正如Darren将其放在评论中:&#34; DoesItLeak can't be a struct&#34;我们不能让DoesItLeak成为结构并安全地解决强引用循环问题。

堆栈框架上存在类似结构的值类型。闭包和类是引用类型。

正如Strong Reference Cycles for Closures section所说:

  

这种强引用循环的发生是因为闭包(如类)是引用类型。

由于结构具有Variable ,并且引用self的闭包使用Variable存储到subscribeNext类中,因此它创建强大的参考周期。请参阅&#34;解决闭包的强引用周期&#34;在Automatic Reference Counting Apple文档中。

答案 1 :(得分:2)

对于仍然面临此问题的任何人。

1)[weak self]是不可能的,因为Struct是value type而不是Reference type,所以没有这样的指针。

2)此处泄漏的主要问题是您试图访问完成块内的Struct属性self.someState = something,这基本上会在分配时创建结构的新副本。

您不应访问完成块内的Struct属性。

答案 2 :(得分:0)

现在禁止在可写上下文中通过转义的闭包捕获自我的模式。快速编译器将发出错误“关闭无法隐式捕获变异的自身参数”。如果上下文是只读的,则可以复制或共享self的值,并且在两种情况下都不会存在引用循环。

答案 3 :(得分:0)

您可以通过创建对闭包捕获的对象的弱引用来解决该问题。

这是没有内存泄漏的示例:

import Foundation
import RxSwift

struct WithoutLeak {

    var someState: String = "initial value"
    var someVariable: Variable<String> = Variable("some stuff")

    let bag = DisposeBag()

    mutating func someFoo() {

        weak let weakSomeState = someState // <-- create a weak reference outside the closure

        someVariable.subscribeNext { person in

            weakSomeState = "something" // <-- use it in the closure
        }
        .addDisposableTo(bag)
    }
}