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 实时数组计数不匹配的主要内容,如果未能解决你的问题,请参考以下文章

Firebase 实时数据库使快照更有价值

Angular 5,订阅firebase,第一个元素是undefined

无法从 firebase 回收器视图中的 firebase 实时数据库中获取嵌套数据

使用 android studio java Recycler 视图从 Firebase 实时数据库中删除一个节点

如何在firebase实时数据库中获取“序列”或类似结构的计数器

如何在后台监听firebase实时数据库更新事件并使用颤振自动启动应用程序(如Messenger中的调用功能)?