Ios 如何从SwiftUI列表和域中删除数据

Ios 如何从SwiftUI列表和域中删除数据,ios,realm,swiftui,swiftui-list,Ios,Realm,Swiftui,Swiftui List,以下代码在SwiftUI列表中正确显示领域数据库中的所有“用户”。我的问题是在我刷行时删除记录 当我刷一行并点击删除按钮时,我立即得到一个未捕获异常错误,列表不会更新,但我知道正确的项目会从领域数据库中删除,因为我下次运行应用程序时,所选记录不会显示 这是我的密码 快捷代码 错误 由于未捕获异常“RLMEException”而终止应用程序,原因:“索引4超出范围(必须小于4)。” 当然,4的变化取决于领域数据库中的项目数量,在这种情况下,当我滑动并点击删除按钮时,我有5条记录 我的期望是,列表将

以下代码在SwiftUI
列表中正确显示
领域
数据库中的所有“用户”。我的问题是在我刷行时删除记录

当我刷一行并点击删除按钮时,我立即得到一个
未捕获异常
错误,
列表
不会更新,但我知道正确的项目会从
领域
数据库中删除,因为我下次运行应用程序时,所选记录不会显示

这是我的密码

快捷代码 错误 由于未捕获异常“RLMEException”而终止应用程序,原因:“索引4超出范围(必须小于4)。”

当然,
4
的变化取决于
领域
数据库中的项目数量,在这种情况下,当我滑动并点击删除按钮时,我有5条记录

我的期望是,
列表
将在每次
allUsers
@状态变量更改时更新,我知道我的问题是不能完全理解绑定是如何工作的

我做错了什么

我的期望是,该列表将在每次 allUsers@状态变量更改

这是正确的,但状态未更改。。。以下几点应该有效

private func deleteRow(with indexSet: IndexSet){
    indexSet.forEach ({ index in
        try! realm.write {
            realm.delete(self.allUsers[index])
        }
    })
    self.allUsers = realm.objects(User.self)     // << refetch !!
}
private func deleteRow(带indexSet:indexSet){
index.forEach({index in
试试看!写吧{
realm.delete(self.alluser[index])
}
})

self.alluser=realm.objects(User.self)/这是处理realm时非常常见的错误。它也发生在“传统”视图控制器中

我发现的唯一一个解决方案是始终使用接口项而不是领域对象,这大大提高了应用程序的稳定性

此外,在现实生活中,我们需要做一些处理,从服务器加载化身图像,添加一些复选框、选择或其他什么,我们通常不需要显示对象的所有属性。不知何故,这是一种MVVM方法

顺便说一下,您可以调用
领域。在循环之前编写
,不确定,但我认为最好尽量减少上下文切换

使用此技术,无论是使用SwiftUI还是UIViewController,都将永远解决RLM崩溃问题

struct ContentView: View {

    struct UserItem: Hashable {
        var id: String
        var name: String
        var age: Int
    }

    private var allUsers: Results<User> = realm.objects(User.self)

    @State private var userItems: [UserItem] = []
    
    func updateItems() {
        userItems = allUsers.map {
            UserItem(id: $0.userID, name: $0.name, age: $0.age)
        }
    }
    
    var body: some View {
        VStack {
            Text("Second Tab")
            List{
                ForEach(userItems, id:\.self) { user in
                    HStack{
                        Text(user.name)
                        Text("\(user.age)")
                    }
                }
                .onDelete(perform: deleteRow)
                
            }
        }.onAppear() {
            updateItems()
        }
    }

    private func deleteRow(with indexSet: IndexSet){
        try! realm.write {
            indexSet.forEach {
                realm.delete(self.allUsers[$0])
            }
        }
        updateItems()
    }
}
struct ContentView:View{
struct UserItem:Hashable{
变量id:String
变量名称:String
变量年龄:Int
}
私有变量alluser:Results=realm.objects(User.self)
@国家私有var userItems:[UserItem]=[]
func updateItems(){
userItems=allUsers.map{
UserItem(id:$0.userID,name:$0.name,age:$0.age)
}
}
var body:一些观点{
VStack{
文本(“第二个选项卡”)
名单{
ForEach(userItems,id:\.self){user in
HStack{
文本(用户名)
文本(“\(user.age)”)
}
}
.onDelete(执行:deleteRow)
}
}.onAppear(){
updateItems()
}
}
private func deleteRow(带indexSet:indexSet){
试试看!写吧{
索引集forEach{
realm.delete(self.alluser[$0])
}
}
updateItems()
}
}

不幸的是,按照您的建议从域中删除记录后重新获取不起作用,我得到了同样的错误。@fs\u tigre不幸的是
由于结果对象的性质,分配初始状态值是不正确的。它们是实时更新的-这意味着域结果对象保持与其子对象的实时连接ng对象,如果一个对象被添加到领域,结果将包括该对象。如果一个对象被删除,该对象将不再包括在这些结果中。可以观察结果对象的更改,然后如果一个对象被添加、修改或删除,就可以采取行动。我很确定
@State
在这里不是正确的事情。任何在哪里可以找到有关如何重构代码的信息?@fs_tigre有时更简单,因此我只需将allUsers结果设置为一个类变量,然后向该变量添加一个观察者。在观察者块中,当某些内容发生更改时,只需刷新tableView。如果tableView中不需要动画UI元素,就可以了。如果确实如此,然后您可以利用observer闭包在更细粒度的行级别控制tableView更新。@fs_tigre,我越想这一点,就越倾向于认为原因是其他地方……如果崩溃是由SwiftUI引起的,则可能是由iOS引起的……如UIKit内部异常或swift库。..但您声明它是RLMEException,这是领域内部异常,而根据提供的代码,由于在写事务中执行删除操作,所有内容都应该是正确的…并且结果应该立即按照设计和记录进行更新。您在哪一行的确切操作上获得此异常?错误指向AppDelegate-
Th阅读1:signal SIGABRT
第一个问题是,在列表或ForEach中传递的数据必须符合可识别的协议。此外,由于结果对象的性质,Realm不太适合SwiftUI-您可能希望暂时依靠通知来处理UI更新。一旦Realm冻结了Objects,它将更容易实现领域功能。因此,如果我正确理解您的意思,您现在说的是,领域和SwiftUI不能很好地配合使用?了解领域端或SwiftUI上的通知?感谢您指出在列表或ForEach中传递的数据必须符合可识别协议的事实。这就是这是我们迄今为止的经验。这不是一个真正的领域“问题”,因为结果按预期工作——这是与SwiftUI性质的交互。这里有许多这样的问题,但没有实际的答案不是解决办法-
private func deleteRow(with indexSet: IndexSet){
    indexSet.forEach ({ index in
        try! realm.write {
            realm.delete(self.allUsers[index])
        }
    })
    self.allUsers = realm.objects(User.self)     // << refetch !!
}
@State private var allUsers: Results<User> = realm.objects(User.self)
struct ContentView: View {

    struct UserItem: Hashable {
        var id: String
        var name: String
        var age: Int
    }

    private var allUsers: Results<User> = realm.objects(User.self)

    @State private var userItems: [UserItem] = []
    
    func updateItems() {
        userItems = allUsers.map {
            UserItem(id: $0.userID, name: $0.name, age: $0.age)
        }
    }
    
    var body: some View {
        VStack {
            Text("Second Tab")
            List{
                ForEach(userItems, id:\.self) { user in
                    HStack{
                        Text(user.name)
                        Text("\(user.age)")
                    }
                }
                .onDelete(perform: deleteRow)
                
            }
        }.onAppear() {
            updateItems()
        }
    }

    private func deleteRow(with indexSet: IndexSet){
        try! realm.write {
            indexSet.forEach {
                realm.delete(self.allUsers[$0])
            }
        }
        updateItems()
    }
}