在 SwiftUI 分组表中按下“编辑模式"按钮之前不会删除行 [英] Row not deleted until Edit Mode button pressed in SwiftUI Grouped Table

查看:21
本文介绍了在 SwiftUI 分组表中按下“编辑模式"按钮之前不会删除行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 ObservableObject 作为数据源在 SwiftUI 中实现了一个分组表.嵌套的 ForEach 用于生成每个部分.EditMode() 按钮切换环境属性.在编辑模式下,当删除操作完成时,被删除的行(意外)保留在屏幕上.(即使该对象已从数据源数组中删除.)当用户返回正常查看模式时,该对象迟早从表中删除.

I implemented a Grouped table in SwiftUI using an ObservableObject as the data source. A nested ForEach is used to generate each section. An EditMode() button toggles that Environment property. In Edit mode, when delete action is completed, the deleted row (unexpectedly)remains on screen. (Even though the object has been removed from the data source array.) When the user returns to normal viewing mode the object is belatedly removed from the table.

为了尝试追踪错误:

  • 数据源对象符合 Hashable、Identifiable 和 Equatable.

  • Data source objects conform to Hashable, Identifiable, and Equatable.

实现了一个简单的删除操作(即删除@Published 属性中的第一个对象)

A simple delete action is implemented (which is to delete the first object in the @Published property)

数据源/视图模型存储在@EnvironmentData 对象中

Data source / view model is stored in an @EnvironmentData object

所以简单的问题是我做错了什么会导致 SwiftUI 没有立即在一个非常简单的(我认为)分组(按部分)列表上反映 EditMode 中的删除操作?

So the simple question is what did I do wrong that would cause SwiftUI not to immediately reflect delete action in EditMode on a very simple (I think) grouped (by Section) List?

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 中

And in SceneDelegate.swift

 // Create the SwiftUI view that provides the window contents.
        let contentView = ContentView().environmentObject(AppData())

推荐答案

我删除了我之前的回答,因为正如你所指出的,虽然它有效但纯属巧合.

I deleted my previous answer, since as you noted, although it worked it was just pure coincidence.

这里你有另一个解决办法.它基本上通过封装第二个ForEach来工作.到目前为止,我发现封装是一个很好的工具,可以规避某些错误.在这种情况下,情况正好相反!

Here you have another work around. It basically works by not encapsulating the second ForEach. So far I found that encapsulating is a good tool for evading certain bugs. In this case it is the opposite!

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())
        }
    }
}

这篇关于在 SwiftUI 分组表中按下“编辑模式"按钮之前不会删除行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆