Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase Realtime Array count mismatch

I have an iOS swift app using Firebase realtime database. If I use the app normally so far I cannot find any issue. However, I want to anticipate edge cases.

I am trying to stress test my app before I push the update, and one way I am doing it is quickly going back and forth from a VC with a tableView to the next VC which is a detail VC. If I do it several times eventually the tableview will show lots of duplicate data.

I have tested my app by having a tableview open on my simulator and going into my Firebase Console and manually changing a value and instantly on the device the string changes.

So I am confused as to why my tableview would show an incorrect amount of children if it is constantly checking what the value should be.

// 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()
                }
            })
        }
    })
}
like image 248
RubberDucky4444 Avatar asked Jun 06 '17 00:06

RubberDucky4444


1 Answers

I got help and changed my code drastically, so now it works

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)
    }

}
like image 71
RubberDucky4444 Avatar answered Nov 11 '22 21:11

RubberDucky4444