44

我们正在尝试尽可能使用 Swift 结构。我们还使用了 RxSwift,它具有采用闭包的方法。当我们有一个结构体创建一个引用自身的闭包时,就会创建一个强引用循环

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 的 Instruments' Allocations 并在Variable< String >中过滤来查看此内存问题

按变量过滤

在此处输入图像描述

如果我尝试使用如下所示的 [weak self],则会收到编译器错误:

someVariable.subscribeNext { [weak self] person in

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

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

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

谢谢你的帮助。

4

4 回答 4

18

正如Darren在评论中所说:“ DoesItLeak 不能是结构”我们不能拥有DoesItLeak结构并安全地解决强引用循环问题。

像结构这样的值类型存在于堆栈帧上。闭包和类是引用类型。

正如闭包的强参考循环部分所说:

之所以会出现这种强引用循环,是因为闭包和类一样,都是引用类型。

由于结构具有Variable ,并且引用的闭包使用self存储到Variable类中subscribeNext,因此它创建了强引用循环。请参阅自动引用计数Apple 文档中的“解决闭包的强引用循环” 。

于 2015-12-22T15:23:05.507 回答
12

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

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

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

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

于 2019-02-11T20:29:52.733 回答
6

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

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

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)
    }
}
于 2019-11-27T17:15:06.490 回答
0

现在不允许在可写上下文中通过转义闭包来捕获 self 的模式。swift 编译器将发出错误“闭包不能隐式捕获变异的自我参数”。如果上下文是只读的,则可以复制或共享 self 的值,并且在任何一种情况下都不会有引用循环。

于 2018-07-26T14:31:37.443 回答