4

这是一个使用 ReactiveSwift 的 Swift 类,将 a 包装MutableProperty在 a 中,并在aProperty中添加对它的订阅:PropertyScopedDisposable

class Leaker {
    let mutableProperty = MutableProperty<Int>(0)

    var wrapperProperty: Property<Int> {
        return Property(self.mutableProperty)
    }

    private var disposable: ScopedDisposable<AnyDisposable>?

    init() {
        let disposable = CompositeDisposable()

        disposable += self.wrapperProperty.producer
            .startWithValues { value in
                print("\(value)")
            }

        self.disposable = ScopedDisposable(disposable)
    }
}

如果我给另一个类一个 type 的属性Leaker?,然后使用 设置它self.leaker = Leaker(),这会造成泄漏。通过“创建泄漏”,我的意思是它触发了泄漏工具,显示了一个标记为 的泄漏对象Malloc 32 Bytes,以及一个包含Leaker.init()调用的堆栈跟踪Leaker.wrapperProperty.getter

为什么会泄漏?我发现很难准确理解是什么导致这里分配的内存永远不会被释放。

其他一些可能有用的事实:

  • mutableProperty如果我直接订阅,这不会泄漏
  • mutableProperty如果我包装在惰性属性而不是计算属性中,这不会泄漏
  • 如果我创建一个临时的,这不会泄漏Leaker,例如let _ = Leaker()
4

1 回答 1

3

我试过了,但无法重现内存泄漏。我已经用Leaker这个代码使用了你的确切类:

final class OtherClass {
  let leaker: Leaker?

  init() {
    self.leaker = Leaker()
  }
}

var otherClass: OtherClass? = OtherClass()

var mutablePropertyCompleted = false
otherClass!.leaker!.mutableProperty.producer.startWithCompleted {
  mutablePropertyCompleted = true
}

var wrappedPropertyCompleted = false
otherClass!.leaker!.wrapperProperty.producer.startWithCompleted {
  wrappedPropertyCompleted = true
}

otherClass = nil

if(!mutablePropertyCompleted) {
  print("LEAK")
}

if(!wrappedPropertyCompleted) {
  print("LEAK")
}

需要注意的一件事是MutableProperty发送completed它的deinit方法,因此应该可以像我在这里所做的那样检测泄漏。

但为了确保我还使用没有检测到任何内容的内存泄漏工具对此进行了分析。

既然您提到了一些不会泄露给您的特定情况,那可能只是我试图重现该问题的方式是错误的,也许您可​​以发布一个完整的示例?

无论如何,我在您发布的示例中没有看到错误,所以要么这是 ReactiveSwift 中的错误,要么是分析器的误报(正如 jjoelson 在他的评论中指出的那样,ReactiveSwift 之前已经发生过这种情况)

于 2017-12-09T13:15:55.347 回答