Swift类释放未发生

xtfmy6hx  于 2023-06-28  发布在  Swift
关注(0)|答案(2)|浏览(168)

我正在编写一个基于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,然后它会释放所有内容)。
显然,这是一个简化的问题示例,但非常重要的是,当文件从列表中删除(或列表被清除)时,立即进行释放,以便正确释放内存。

kkbh8khc

kkbh8khc1#

我认为这里的问题是对内存管理的误解。TestView是一个结构体;它不需要进行内存管理,就像你想的那样。因此,在TestView被另一个TestView替换之前,没有什么可以触发内存清理,并且您无法控制何时发生(这与绘制视图的需要有关)。同时,ViewModel是一个@StateObject,所以它的工作是 * 持久化 *(这就是状态对象的含义),所以它也不会被释放。因此,没有特别的理由说明为什么应按需释放其FileItem属性。
当文件从列表中删除(或列表被清除)时,立即进行释放,以便正确释放内存,这一点非常重要
真的吗?这些FileItem是很小的对象;我们能谈论多少内存?它根本不可能是重要的。如果在真实的生活中,FileItem具有某个大类示例作为属性,那么您应该向我们展示这一点。在这种情况下,不要只是将文件项列表设置为空列表或其他什么,而是首先将 *that属性 * 设置为nil或其他一些“空”选项。

x9ybnkn6

x9ybnkn62#

以下是其他需要解决这个问题的人的答案。
在视图中,创建一个@State变量,如下所示:

@State private var refreshID = UUID()

然后,在列表的末尾放置两个修饰符来标识列表,并监视数组的onChange,如下所示:

List {
    // All the list code
}
.id(refreshID)
.onChange(of: myArray) { _ in
    refreshID = UUID()
}

不幸的是,视图不会自动更新,直到用户的下一次交互,但这不是一个大问题,因为如果用户不再与应用交互,我们不需要担心释放。一旦它们与应用程序中的任何其他元素交互,就会发生解除分配。
希望这有帮助!

相关问题