Firebase 实时数组计数不匹配
Posted
技术标签:
【中文标题】Firebase 实时数组计数不匹配【英文标题】:Firebase Realtime Array count mismatch 【发布时间】:2017-06-06 00:18:49 【问题描述】:我有一个使用 Firebase 实时数据库的 ios swift 应用程序。如果我到目前为止正常使用该应用程序,我找不到任何问题。但是,我想预测边缘情况。
我正在尝试在推送更新之前对我的应用程序进行压力测试,我这样做的一种方法是快速地从带有 tableView 的 VC 到下一个 VC 来回切换,这是一个详细的 VC。如果我多次这样做,最终表格视图将显示大量重复数据。
我通过在我的模拟器上打开一个 tableview 并进入我的 Firebase 控制台并手动更改一个值并立即在设备上更改字符串来测试我的应用程序。
所以我很困惑,如果我的 tableview 不断检查值应该是什么,为什么它会显示不正确的孩子数量。
// MARK: Firebase Methods
func checkIfDataExits()
DispatchQueue.main.async
self.cardArray.removeAll()
self.ref.observe(DataEventType.value, with: (snapshot) in
if snapshot.hasChild("cards")
self.pullAllUsersCards()
else
self.tableView.reloadData()
)
func pullAllUsersCards()
cardArray.removeAll()
let userRef = ref.child("users").child((user?.uid)!).child("cards")
userRef.observe(DataEventType.value, with: (snapshot) in
for userscard in snapshot.children
let cardID = (userscard as AnyObject).key as String
let cardRef = self.ref.child("cards").child(cardID)
cardRef.observe(DataEventType.value, with: (cardSnapShot) in
let cardSnap = cardSnapShot as DataSnapshot
let cardDict = cardSnap.value as! [String: AnyObject]
let cardNickname = cardDict["nickname"]
let cardType = cardDict["type"]
let cardStatus = cardDict["cardStatus"]
self.cardNicknameToTransfer = cardNickname as! String
self.cardtypeToTransfer = cardType as! String
let aCard = CardClass()
aCard.cardID = cardID
aCard.nickname = cardNickname as! String
aCard.type = cardType as! String
aCard.cStatus = cardStatus as! Bool
self.cardArray.append(aCard)
DispatchQueue.main.async
self.tableView.reloadData()
)
)
【问题讨论】:
我需要在 numberOfItemsInSection 上使用 firebase 方法吗? 不确定我们看到的代码是否足够。像 viewDid/WillAppear 这样的东西会很有帮助,表方法和包含表数据的数组上的任何 setter/getter 属性也会很有帮助。通常,当表中存在重复数据的问题时,这是因为表的数据数组在重新加载之前没有被清除。当您在两个不同的视图之间来回切换时,例如 viewWillAppear 中的任何内容都会在您每次切换回表格视图时被调用。 【参考方案1】:我得到了帮助并彻底改变了我的代码,所以现在它可以工作了
func checkIfDataExits()
self.ref.observe(DataEventType.value, with: (snapshot) in
if snapshot.hasChild("services")
self.pullCardData()
else
DispatchQueue.main.async
self.collectionView.reloadData()
)
func pullCardData()
let cardRef = self.ref.child("cards")
cardRef.observe(DataEventType.value, with: (snapshot) in
for cards in snapshot.children
let allCardIDs = (cards as AnyObject).key as String
if allCardIDs == self.cardID
if let childId = self.cardID
let thisCardLocation = cardRef.child(childId)
thisCardLocation.observe(DataEventType.value, with: (snapshot) in
let thisCardDetails = snapshot as DataSnapshot
if let cardDict = thisCardDetails.value as? [String: AnyObject]
self.selectedCard?.cardID = thisCardDetails.key
self.selectedCard?.nickname = cardDict["nickname"] as? String ?? ""
self.selectedCard?.type = cardDict["type"] as? String ?? ""
self.pullServicesForCard()
)
)
func pullServicesForCard()
if let theId = self.cardID
let thisCardServices = self.ref.child("cards").child(theId).child("services")
thisCardServices.observe(DataEventType.value, with: (serviceSnap) in
if self.serviceArray.count != Int(serviceSnap.childrenCount)
self.serviceArray.removeAll()
self.fetchAndAddAllServices(serviceSnap: serviceSnap, index: 0, completion: (success) in
if success
DispatchQueue.main.async
self.collectionView.reloadData()
)
)
func fetchAndAddAllServices(serviceSnap: DataSnapshot, index: Int, completion: @escaping (_ success: Bool) -> Void)
if serviceSnap.hasChildren()
if index < serviceSnap.children.allObjects.count
let serviceChild = serviceSnap.children.allObjects[index]
let serviceID = (serviceChild as AnyObject).key as String
let thisServiceLocationInServiceNode = self.ref.child("services").child(serviceID)
thisServiceLocationInServiceNode.observeSingleEvent(of: DataEventType.value, with: (thisSnap) in
let serv = thisSnap as DataSnapshot
if let serviceDict = serv.value as? [String: AnyObject]
let aService = ServiceClass(serviceDict: serviceDict)
self.serviceCurrent = serviceDict["serviceStatus"] as? Bool
self.serviceName = serviceDict["serviceName"] as? String ?? ""
self.serviceURL = serviceDict["serviceURL"] as? String ?? ""
self.serviceFixedBool = serviceDict["serviceFixed"] as? Bool
self.serviceFixedAmount = serviceDict["serviceAmount"] as? String ?? ""
self.attentionInt = serviceDict["attentionInt"] as? Int
self.totalArr.append((serviceDict["serviceAmount"] as? String)!)
// self.doubleArray = self.totalArr.flatMap Double($0)
// let arraySum = self.doubleArray.reduce(0, +)
// self.title = self.selectedCard?.nickname ?? ""
// if let titleName = self.selectedCard?.nickname
// self.title = "\(titleName): \(arraySum)"
//
aService.serviceID = serviceID
if serviceDict["serviceStatus"] as? Bool == true
self.selectedCard?.cStatus = true
else
self.selectedCard?.cStatus = false
if !self.serviceArray.contains(where: (service) -> Bool in
return service.serviceID == aService.serviceID
)
self.serviceArray.append(aService)
self.serviceArray.sort $1.serviceAttention < $0.serviceAttention
self.fetchAndAddAllServices(serviceSnap: serviceSnap, index: index + 1, completion: completion)
)
else
completion(true)
else
completion(false)
【讨论】:
看起来不错,我建议在这里使用一些保护语句。通常当我有很多 if-else 时我会做一些事情(我是这样视觉化的,有助于玩展开的 vars imo)。 @murphguy 是的,我有很多需要改进的地方...guard 就是其中之一以上是关于Firebase 实时数组计数不匹配的主要内容,如果未能解决你的问题,请参考以下文章
Angular 5,订阅firebase,第一个元素是undefined
无法从 firebase 回收器视图中的 firebase 实时数据库中获取嵌套数据
使用 android studio java Recycler 视图从 Firebase 实时数据库中删除一个节点