swiftui - 在 SwiftUI 分组表中按下编辑模式按钮之前不会删除行
问题描述
我使用 ObservableObject 作为数据源在 SwiftUI 中实现了一个分组表。嵌套的 ForEach 用于生成每个部分。EditMode() 按钮切换该 Environment 属性。在编辑模式下,当删除操作完成时,被删除的行(意外地)保留在屏幕上。(即使该对象已从数据源数组中删除。)当用户返回正常查看模式时,该对象迟迟会从表中删除。
为了尝试追踪错误:
数据源对象符合 Hashable、Identifiable 和 Equatable。
实现了一个简单的删除操作(即删除@Published 属性中的第一个对象)
数据源/视图模型存储在@EnvironmentData 对象中
所以简单的问题是我做错了什么会导致 SwiftUI 不会立即在一个非常简单的(我认为)分组(按部分)列表上反映 EditMode 中的删除操作?
struct ContentView: View {
@EnvironmentObject var vm: AppData
var body: some View {
NavigationView {
List {
ForEach(vm.folderSource) { (folder: Folder) in
return Section(header: Text(folder.title)) {
//this is where problem originates. When I drop in a new full-fledged View struct, UI updates stop working properly when .onDelete is called from this nested View
FolderView(folder: folder)
}
}
}.listStyle(GroupedListStyle())
.navigationBarItems(trailing: EditButton())
}
}
}
struct FolderView: View {
var folder: Folder
@EnvironmentObject var vm: AppData
var body: some View {
//I'm using a dedicated View inside an outer ForEach loop to be able to access a data-source for each dynamic view.
let associatedProjects = vm.projects.filter{$0.folder == folder}
return ForEach(associatedProjects) { (project: Project) in
Text(project.title.uppercased())
// dumbed-down delete, to eliminate other possible issues preventing accurate Dynamic View updates
}.onDelete{index in self.vm.delete()}
}
}
//view model
class AppData: ObservableObject {
let folderSource: [Folder]
@Published var projects: [Project]
func delete() {
//dumbed-down static delete call to try to find ui bug
self.projects.remove(at: 0)
//
}
init() {
let folders = [Folder(title: "folder1", displayOrder: 0), Folder(title: "folder2", displayOrder: 1), Folder(title: "folder3", displayOrder: 2) ]
self.folderSource = folders
self.projects = {
var tempArray = [Project]()
tempArray.append(Project(title: "project 0", displayOrder: 0, folder: folders[0] ))
tempArray.append(Project(title: "project 1", displayOrder: 1, folder: folders[0] ))
tempArray.append(Project(title: "project 2", displayOrder: 2, folder: folders[0] ))
tempArray.append(Project(title: "project 3", displayOrder: 0, folder: folders[1] ))
tempArray.append(Project(title: "project 4", displayOrder: 1, folder: folders[1] ))
tempArray.append(Project(title: "project 5", displayOrder: 2, folder: folders[1] ))
tempArray.append(Project(title: "project 6", displayOrder: 0, folder: folders[2] ))
tempArray.append(Project(title: "project 7", displayOrder: 1, folder: folders[2] ))
tempArray.append(Project(title: "project 8", displayOrder: 2, folder: folders[2] ))
return tempArray
}()
}
}
//child entity many-to-one (Folder)
class Project: Hashable, Equatable, Identifiable {
let id = UUID()
let title: String
let displayOrder: Int
let folder: Folder
init(title: String, displayOrder: Int, folder: Folder) {
self.title = title
self.displayOrder = displayOrder
self.folder = folder
}
static func == (lhs: Project, rhs: Project) -> Bool {
lhs.id == rhs.id
}
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
//parent entity: Many Projects have one Folder
class Folder: Hashable, Equatable, Identifiable {
let id = UUID()
let title: String
let displayOrder: Int
init(title: String, displayOrder: Int) {
self.title = title
self.displayOrder = displayOrder
}
//make Equatable
static func == (lhs: Folder, rhs: Folder) -> Bool {
lhs.id == rhs.id
}
//make Hashable
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
在 SceneDelegate.swift
// Create the SwiftUI view that provides the window contents.
let contentView = ContentView().environmentObject(AppData())
解决方案
我删除了我之前的答案,因为正如你所指出的,虽然它有效,但这纯粹是巧合。
在这里,您还有另一项工作。它基本上通过不封装第二个ForEach来工作。到目前为止,我发现封装是规避某些错误的好工具。在这种情况下,情况正好相反!
struct ContentView: View {
@EnvironmentObject var vm: AppData
var body: some View {
NavigationView {
List {
ForEach(vm.folderSource) { (folder: Folder) in
Section(header: Text(folder.title)) {
// FolderView(folder: folder)
ForEach(self.vm.projects.filter{$0.folder == folder}) { (project: Project) in
Text(project.title.uppercased())
}.onDelete{index in
self.vm.delete()
}
}
}
}
.listStyle(GroupedListStyle())
.navigationBarItems(trailing: EditButton())
}
}
}
推荐阅读
- python - 如何在多索引数据帧的最外层使用 iloc 切片?
- java - 使用 ClientCredentialProvider 发送电子邮件无法找到租户 guid
- python - 转换为字典python中的可执行值
- kubernetes - 使用 OPA 进行 Envoy 外部授权 - 使用大型 JSON 主体评估失败
- swift - 提取 HKCategoryValueAppleStandHour(枚举 Int)的 HealthKit/Swift 语法?
- python - 在 Django 中链接应用程序的正确方法是什么?
- powershell - 替换文件中的文本并保存的功能
- azure - PowerBI 使用 Data Bricks 使用 Azure Data Lake GEN1
- twitter-bootstrap - 从引导程序 3 升级到 4 后 flexbox 列中断的问题
- python - 一个小部件相对于另一个小部件位置的定位问题