这似乎应该有一个非常简单的答案。
我正在使用SwiftUI和firebase实时数据库构建一个应用程序。该数据库将有一个名为items
的节点,该节点有大量子节点,数量约为1000。我希望该应用程序在启动时加载该节点子节点的内容,然后收听firebase以备将来添加子节点。想象一下:
struct Item { … } // some struct
var items: [Item] = []
let itemsRef = Database.database().reference().child("items")
根据firebase,这个调用应该一次加载一个所有的子级,然后在添加到firebase中的items
节点时添加新的子级:
itemsRef.observe(.childAdded) { snapshot in
// add a single child based on snapshot
items.append(Item(fromDict: snapshot.value as! [String:String])
}
这就完成了任务,但与使用他们提供的getData()
方法相比,效率似乎非常低,后者为我们提供了一个包含所有子项的字典:
itemsRef.getData() { error, snapshot in
// set all children at once base on snapshot
items = Item.itemArray(fromMetaDict: snapshot.value as! [String:[String:String]])
}
最初最好使用getData()
,然后使用observe(.childAdded)
来监视添加。但是,当observe
完成块启动时,我们如何防止它运行1000次呢?燃烧基地的医生说这就是将要发生的事情:
此事件为每个现有子级触发一次,然后在每次将新子级添加到指定路径时再次触发。
提前感谢!
附言:我认为没有必要包括函数Item.init(fromDict:)
或Item.itemArray(fromMetaDict:)
的定义——希望它们的作用很清楚
在路径上侦听.childAdded
与在同一路径上侦听.value
或调用`getData((没有区别。区别纯粹是客户端的,有线通信是(或:应该是(相同的。
事实上,监听.child*
事件以操作某些数据结构/UI,然后监听.value
事件以提交这些更改是很常见的,因为.value
保证在所有相应的.child*
之后激发。
在.value
或getData()
中执行第一大批数据,然后使用.child*
进行细粒度更新的一个常见技巧是使用布尔标志来指示您是否已经获得了初始数据,并在初始时将if设置为false
。
在.child*
处理程序中,仅当标志为true时才处理数据。
itemsRef.observe(.childAdded) { snapshot in
if isInitialDataProcessed {
items.append(Item(fromDict: snapshot.value as! [String:String])
}
}
然后在.value
/getData
处理程序中,处理数据,然后将标志设置为true。