我在使用 SwiftUI 的
以下是重现步骤:
1. 创建一个新的空白 SwiftUI macOS 项目。 2. 粘贴以下代码:
List
和 id: \.self
时出现了奇怪的内存泄漏问题,只有一些项目被销毁。我正在使用 macOS Monterey Beta 5。以下是重现步骤:
1. 创建一个新的空白 SwiftUI macOS 项目。 2. 粘贴以下代码:
class Model: ObservableObject {
@Published var objs = (1..<100).map { TestObj(text: "\($0)")}
}
class TestObj: Hashable {
let text: String
static var numDestroyed = 0
init(text: String) {
self.text = text
}
static func == (lhs: TestObj, rhs: TestObj) -> Bool {
return lhs.text == rhs.text
}
func hash(into hasher: inout Hasher) {
hasher.combine(text)
}
deinit {
TestObj.numDestroyed += 1
print("Deinit: \(TestObj.numDestroyed)")
}
}
struct ContentView: View {
@StateObject var model = Model()
var body: some View {
NavigationView {
List(model.objs, id: \.self) { obj in
Text(obj.text)
}
Button(action: {
var i = 1
model.objs.removeAll(where: { _ in
i += 1
return i % 2 == 0
})
}) {
Text("Remove half")
}
}
}
}
- 运行该应用,并点击“删除一半”按钮,保持点击直到所有项都被删除。然而,如果你查看控制台,你会发现只有85个项目被销毁了,而实际上有99个项目。Xcode内存图也证明了这一点。
这似乎是由id: \.self
这行代码引起的。将其删除并替换为id: \.text
即可解决问题。
但我使用id: \.self
的原因是我想支持多重选取,并且我希望选择的类型是Set<TestObj>
,而不是Set<UUID>
。
有没有什么办法可以解决这个问题?
id
设为UUID()
呢?另外,我并不太明白你所说的“我想支持多选,并且我想获取选择中对象的实际引用” -List
仍然可以通过obj
提供对对象的引用。ID只是一个唯一且恒定的值,用于标识列表中的每一行。 - GeorgeTestObj
时,我必须扫描数组(这在有数千个项目的情况下效率不高)。 - recaptchaid:
部分,那么选择的类型也必须更改。(它取决于id:
是什么) - recaptchaid
的同时使选择功能在List
中工作的方法是向列表行添加.tag(obj)
修饰符,但是一些行仍然没有被释放(测试中约有42个 deinit,而之前为0)。我认为解决方案可能类似于 Swift Collection 的 OrderedDictionary。这样可以保存对象,但每个对象的键是id
。然后,您可以在 O(1) 时间内访问它们,并且将不再通过引用类型来标识或标记项目。 - George