我正在编写一个基于SwiftUI的Mac OS应用程序,它显示添加的文件列表,并允许用户选择它们,并从列表中删除一个或多个选定的文件,或者从列表中删除所有内容。
为了实现这一点,我有一个类、一个视图和一个视图模型。
类是:
class FileItem: Hashable, Identifiable {
var id = UUID()
var fileName: String
init(
fileName: String
) {
self.fileName = fileName
print("Class Initialized")
}
deinit {
print("Class DeInitialized")
}
static func == (lhs: FileItem, rhs: FileItem) -> Bool {
return lhs.fileName == rhs.fileName
}
func hash(into hasher: inout Hasher) {
hasher.combine(fileName)
}
}
视图模型为:
extension TestView {
@MainActor
class ViewModel: ObservableObject {
@Published var myFiles: [FileItem?] = []
@Published var fileSelection: Set<FileItem> = []
func fileRemove() {
for entry in self.fileSelection {
if let idx = self.myFiles.firstIndex(where: { $0 == entry }) {
self.fileEntries.remove(at: idx)
}
self.fileSelection = []
}
}
func fileRemoveAll() {
self.myFiles = []
self.fileSelection = []
}
}
}
该视图是:
struct TestView: View {
@StateObject var viewModel: ViewModel
var body: some View {
VStack {
Button {
viewModel.fileRemove()
} label: {
Text("Remove Selected")
}
Button {
viewModel.fileRemoveAll()
} label: {
Text("Remove All")
}
List(selection: $viewModel.fileSelection) {
ForEach(viewModel.myFiles.compactMap { $0 }, id: \.self) { file in
Text(file.fileName)
}
.onMove { indices, destination in
viewModel.myFiles.move(
fromOffsets: indices,
toOffset: destination
)
}
}
}
}
问题是,当我使用fileRemove时,没有任何东西被释放。直到myFiles完全为空,所有内容才会立即释放。
另一个问题是,即使myFiles是[],在应用进入后台之前,什么都不会被释放(即我点击XCode,然后它会释放所有内容)。
显然,这是一个简化的问题示例,但非常重要的是,当文件从列表中删除(或列表被清除)时,立即进行释放,以便正确释放内存。
2条答案
按热度按时间kkbh8khc1#
我认为这里的问题是对内存管理的误解。TestView是一个结构体;它不需要进行内存管理,就像你想的那样。因此,在TestView被另一个TestView替换之前,没有什么可以触发内存清理,并且您无法控制何时发生(这与绘制视图的需要有关)。同时,ViewModel是一个
@StateObject
,所以它的工作是 * 持久化 *(这就是状态对象的含义),所以它也不会被释放。因此,没有特别的理由说明为什么应按需释放其FileItem属性。当文件从列表中删除(或列表被清除)时,立即进行释放,以便正确释放内存,这一点非常重要
真的吗?这些FileItem是很小的对象;我们能谈论多少内存?它根本不可能是重要的。如果在真实的生活中,FileItem具有某个大类示例作为属性,那么您应该向我们展示这一点。在这种情况下,不要只是将文件项列表设置为空列表或其他什么,而是首先将 *that属性 * 设置为
nil
或其他一些“空”选项。x9ybnkn62#
以下是其他需要解决这个问题的人的答案。
在视图中,创建一个@State变量,如下所示:
然后,在列表的末尾放置两个修饰符来标识列表,并监视数组的onChange,如下所示:
不幸的是,视图不会自动更新,直到用户的下一次交互,但这不是一个大问题,因为如果用户不再与应用交互,我们不需要担心释放。一旦它们与应用程序中的任何其他元素交互,就会发生解除分配。
希望这有帮助!