以下示例显示了MyView
内部的视图(List
)。点击后,将其完全删除。但是,它的内存永远不会释放。
这很明显,但是MyView具有SomeClass类型的属性,并且从未调用其deinit
的事实。但是,如果在List
之外拍摄,则视图已正确放置。
这是另一个错误吗?
import SwiftUI
struct ContentView : View {
@State private var showView = true
var body: some View {
VStack {
List {
if showView {
MyView().tapAction {
self.showView.toggle()
}
}
}
}
}
}
struct MyView: View {
private var myVar = SomeClass()
var body: some View {
Text("Tap me to Remove!")
}
}
class SomeClass {
init() { }
deinit {
print("deinit SomeClass")
}
}
但是,在这种情况下,deinit
被正确调用。唯一的区别是在这里我不使用List
。
struct ContentView : View {
@State private var showView = true
var body: some View {
VStack {
if showView {
MyView().tapAction {
self.showView.toggle()
}
}
}
}
}
答案 0 :(得分:1)
我认为这是一个错误。但是如果您将列表更改为
List(0...0) { _ in
if self.showView {
MyView().tapAction {
self.showView.toggle()
}
}
}
无法正常工作,所有Scrollable视图(例如ScrollView或Form)也存在问题
答案 1 :(得分:1)
实际上这不是错误。 List
的工作方式有所不同(有点像应用了一些android逻辑)。由于项目是可重用的,并且隐藏/显示操作是列表中非常常见的操作,因此它们决定将项目保留在内存中,以防万一您决定将其还原(就像android处理活动的方式一样)。
仅当其他尝试替换它们时,它们才被取消初始化。尝试使用此代码并研究UUID,以了解自己。我敢打赌,您会对结果感到震惊:
struct ContentView: View {
@State private var items = [0, 1, 2, 3]
var body: some View {
VStack {
List(items) { id in
MyView().tapAction {
print("Tapped")
self.items.removeLast()
}
}
}
}
}
struct MyView: View {
private var myVar = SomeClass()
var body: some View {
Text("Tap me to Remove!")
}
}
class SomeClass {
init() {
id = UUID().uuidString
print("Init id: \(id)")
}
let id: String
deinit {
print("deinit id: \(id)")
}
}
如您所见,当您从列表中删除某项时,令人惊讶的是其余项被取消了初始化。因为这些被替换了,而不是您要删除的那个。
请注意,此行为尚未记录(可能),将来可能会改变。