将 Firebase 实时数据库与 SwiftUI 列表一起使用 - 清除列表

Using Firebase Realtime Database with SwiftUI List - Clearing a list

我想知道通过可观察对象清除视图中显示的列表数据的最有效方法是什么?目前,每次我重新加载视图时,数据都会重复(因为我们正在检查更新查询和解析响应)。这不是预期的行为。预期的行为是仅更新 @Published 属性 "if" 数据库指示已收到新通知。

我知道罪魁祸首是 .onAppear 块中的代码 - 我只是不确定在架构上如何解决这个问题。我如何在仅解析新数据而不解析之前解析的数据时使用此侦听器?

我试图清除列表 .onAppear,但导致崩溃,表明我试图删除一个部分,而已经有 0 个部分,所以没有成功。

我考虑过可能为 Message 对象提供静态唯一 ID,以便在发送到 Firebase 时与 Message 对象一起上传(或使用 firebase 密钥本身)。这样我就可以使用一组使用唯一 ID 的字典对象来标识字典中的对象。这可能会帮助我避免重复输入。

struct Updates: View {
    @ObservedObject var dataController = DataController()
    var body: some View {
        ZStack {

            VStack {

                List {

                    ForEach(self.dataController.messages, id: \.id) { message in
                            Text(message.message)
                        }

                    }
                }.onAppear {

                    self.dataController.query.observe(.childAdded) { snapshot in
                        let data = JSON(snapshot.value as Any)

                        if let message = Message.parseFirebaseQuery(dataJSON: data){
                            self.dataController.messages.append(message)
                        }
                    }
                }
        }
    }
}
class DataController: ObservableObject {

    @Published var query = ChatPathsAndReferences.refs.databaseMessages.queryLimited(toLast:100).queryOrdered(byChild: "date")
    @Published var messages = [Message]()

}

我通过向我的 ObservableObject 添加一个 init 块解决了这个问题

class DataController: ObservableObject {

    @Published var query = ChatPathsAndReferences.refs.databaseMessages.queryLimited(toLast:100).queryOrdered(byChild: "date")
    @Published var messages = [Message]()

    init() {
       self.query.observe(.childAdded) { snapshot in
          let data = JSON(snapshot.value as Any)
       
          if let chatMessage = ChatMessage.parseFirebaseQuery(dataJSON: data){
             self.messages.append(chatMessage)
          }
       }
   }
}

所以现在,当我创建视图时,对象会在数据控制器而不是视图中初始化观察者。

struct Updates: View {
   // As you can see, we initialise the data controller which inits the observer. 
   // Since the messages in the data controller are @Published, 
   // we don't need to worry about checking for updates again in the view
    @ObservedObject var chatDataController: DataController = DataController()
    
    var body: some View {
        GeometryReader { geometry in
            ZStack {
                Color("Background")
                
                VStack {

                    // messages
                    List {
                        ForEach(self.chatDataController.messages, id: \.id) { message in
                                Text(message.message)
                        }
                    }
            }
        }
    }

}