【问题标题】:Using Firebase Realtime Database with SwiftUI List - Clearing a list将 Firebase 实时数据库与 SwiftUI 列表一起使用 - 清除列表
【发布时间】:2020-04-13 16:03:13
【问题描述】:

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

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

我试图清除列表 .onAppear,但导致崩溃表明我试图删除一个部分,而已经有 0 个部分,所以这不起作用。

我考虑过在发送到 Firebase(或使用 firebase 密钥本身)时,可能会为 Message 对象提供静态唯一 ID 以与 Message 对象一起上传。这样我就可以使用一组使用唯一 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]()

}

【问题讨论】:

  • 我不确定,但我认为这种方法会有问题。使用 Firebase,您无需像 Firebase 那样添加观察者。换句话说,向节点添加 .childAdded 观察者将在将子节点添加到该节点时自动向应用程序发送事件。我认为这段代码的方式是,你正在观察一个观察者。此外,您说 .onAppear 是罪魁祸首是正确的,因为每次视图出现时都会重新运行代码。我建议在第一次实例化视图时使用自定义初始化程序 init(_ 来设置 firebase 观察者。
  • 这个自定义初始化会执行一次吗?还是每次我换出视图并返回视图时它会不断初始化?
  • 它会在视图实例化时执行。 .onAppear 在视图出现/消失/出现等时执行。
  • @Karim,你最终解决了这个问题吗?
  • 嘿@Xeaza,是的,我做到了。我将在下面发布答案以查看过程。

标签: swift firebase firebase-realtime-database swiftui swiftui-list


【解决方案1】:

我通过向我的 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)
                        }
                    }
            }
        }
    }

}

【讨论】:

  • 感谢您的回复!我最终在自己的实例中发现的是,我没有在快照侦听器的完成块内重置我的数组。因此,旧数组 + 新项被附加到旧项数组中。 ?‍♂️ 在得到这个平方之后,我的列表正确更新并显示了正确数量的项目。
  • 您是否特别需要每次都重置阵列?我认为在 Firebase 中使用可观察查询的目的是让您只需要监听“更新”,这就是我第一次重新考虑我的方法的原因。只是对你想要达到的目标感到好奇,仅此而已! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-03
  • 2020-03-25
  • 2020-05-31
  • 2017-05-06
  • 2019-10-17
  • 2021-06-21
  • 2021-10-16
相关资源
最近更新 更多