0

I have a function that listen to Firebase for added and removed childs in my database. I do a print for the array where I store incoming data from database before observers and one after the observers so to check if the logic is working, and it does. Snapshots append and remove the right object to/from the array.

Now I have the problem that on console I get more than one print per call, in both .childAdded and .childRemoved. It's not random, from fresh start the pattern goes like, 1st add to Firebase gives me 2 prints. And from than it's incremental. 2nd add or 1st remove will give me 3 prints. etc etc.. It's almost like it has a counter.. Removing the observers in viewWillDisappeardoesn't change anything..

In Firebase I store MKAnnotation's coordinates. When I add one annotation I post it, I get it back through the observer's snapshotand I add it to the map. When I remove it I remove it from Firebase and I get a snapshot from .childRemovedobserver and I update the map. What I noticed by putting a breakpoint for each observer is that on the.childRemovedit loops incrementally as the prints. That should mean that the annotation gets added that number of times to the map by the .chilAddedobserver right? I thought I solved this but it's so clear that I haven't. Can you spot the problem here? Many thanks as usual Here's the function:

func getAlerts(setCompletion: @escaping (Bool) -> ()) {

        self.mapView.removeAnnotations(mapView.annotations)
        MapArray.alertNotificationCoordinatesArray.removeAll()
        MapArray.userAlertNotificationArray.removeAll()

        print("                     MapArray.alertNotificationCoordinatesArray before getNewerAlerts is: \(MapArray.alertNotificationCoordinatesArray)")
        print("                     self.userAlertNotificationArray before getNewerAlerts is: \(MapArray.userAlertNotificationArray)")

        ref = Database.database().reference()
        ref?.child("Continent").child("Europe").child("Country").child("Italy").child("Region").child("Emilia-Romagna").child("City").child("Bologna").child("Community").child("Alert Notifications").observe(.childAdded, with: { (snapshot) in
            //            self.mapView.removeAnnotations(self.mapView.annotations) //
            print("        added snapshot is: \(snapshot)")
            guard let data = snapshot.value as? [String:String] else { return }
//            guard let firebaseKey = snapshot.key as? String else { return }
            let firebaseKey = snapshot.key
            //                let date = data!["Date"]
            //                let time = data!["Time"]
            let dataLatitude = data["Latitude"]!
            let dataLongitude = data["Longitude"]!

            let type = data["Description"]!
            let id = Int(data["Id"]!)
            let userName = data["user"]!
            let doubledLatitude = Double(dataLatitude)
            let doubledLongitude = Double(dataLongitude)
            let recombinedCoordinate = CLLocationCoordinate2D(latitude: doubledLatitude!, longitude: doubledLongitude!)

            let userAlertAnnotation = UserAlert(type: type, coordinate: recombinedCoordinate, firebaseKey: firebaseKey, title: type,id: id!, userName: userName)
            MapArray.userAlertNotificationArray.append(userAlertAnnotation)  // array of notifications coming from Firebase
            MapArray.alertNotificationCoordinatesArray.append(recombinedCoordinate) // array for checkig alerts on route
                        print("                 MapArray.alertNotificationCoordinatesArray after getNewerAlerts is: \(MapArray.alertNotificationCoordinatesArray)")
                        print("                     self.userAlertNotificationArray after getNewerAlerts is: \(MapArray.userAlertNotificationArray)")
            setCompletion(true)
            self.mapView.addAnnotations(MapArray.userAlertNotificationArray)
        })

        ref?.child("Continent").child("Europe").child("Country").child("Italy").child("Region").child("Emilia-Romagna").child("City").child("Bologna").child("Community").child("Alert Notifications").observe(.childRemoved, with: { (snapshot) in

            print("    self.userAlertNotificationArray before getDeletedAlerts snapshot is: \(MapArray.userAlertNotificationArray)")
            print("    MapArray.alertNotificationCoordinatesArray before getDeletedAlerts snapshot is: \(MapArray.alertNotificationCoordinatesArray)")

            print("        removed snapshot is: \(snapshot)")
            guard let data = snapshot.value as? [String:String] else { return }
            let firebaseKey = snapshot.key
            //                let date = data!["Date"]
            //                let time = data!["Time"]
            let dataLatitude = data["Latitude"]!
            let dataLongitude = data["Longitude"]!

            let type = data["Description"]!
            let id = Int(data["Id"]!)
            let userName = data["user"]!
            let doubledLatitude = Double(dataLatitude)
            let doubledLongitude = Double(dataLongitude)
            let recombinedCoordinate = CLLocationCoordinate2D(latitude: doubledLatitude!, longitude: doubledLongitude!)


            _ = UserAlert(type: type, coordinate: recombinedCoordinate, firebaseKey: firebaseKey, title: type,id: id!, userName: userName)

            MapArray.userAlertNotificationArray.removeAll(where: { ($0.firebaseKey == firebaseKey) }) //remove the alert
            MapArray.alertNotificationCoordinatesArray.removeAll(where: { ($0.latitude == recombinedCoordinate.latitude && $0.longitude == recombinedCoordinate.longitude) })

            self.mapView.removeAnnotations(self.mapView.annotations)
            self.mapView.addAnnotations(MapArray.userAlertNotificationArray)

                        print("    self.userAlertNotificationArray after getDeletedAlerts snapshot is: \(MapArray.userAlertNotificationArray)")
                        print("    MapArray.alertNotificationCoordinatesArray after getDeletedAlerts snapshot is: \(MapArray.alertNotificationCoordinatesArray)")
            setCompletion(true)
        })


    }
Vincenzo
  • 5,304
  • 5
  • 38
  • 96
  • That is a normal behavior of `.observe` if you want the data to come only once and detach the observer, then use `.observeSingleEvent` – Galo Torres Sevilla Mar 22 '19 at 22:00
  • @GaloTorresSevilla Well, `.observeSingleEvent`i s how I had it before rewriting the function and I had the same behaviour. Anyways, how can be it normal that it loops an incremental number of times? – Vincenzo Mar 22 '19 at 22:09
  • Try reading the documentation here: https://firebase.google.com/docs/database/ios/read-and-write it is pretty well explained as why events are fired several times when `.observe` is used – Galo Torres Sevilla Mar 22 '19 at 22:23
  • @GaloTorresSevilla I found that using `.observeSingleEvent`only reads existing childs but doesn't get new ones as they get added from different users.. using `.observe(.childAdded` gives me multiple reads of the newer added child .. but using `.observe(DataEventType.childAdded`gives me existing childs and a child only when it gets added or deleted. It now works as I intended it to be. So, if I got right, I just wrongly wrote the observer right? I actually omitted the` (DataEventType`because I read it as a solution in some post here. Thank you so much for pointing me in the right direction. – Vincenzo Mar 22 '19 at 23:11
  • and actually got an answer to another question https://stackoverflow.com/questions/54958223/childadded-observer-doesnt-get-called-if-the-function-is-not-called-explicitly/54969563#54969563 that used `.observe(.childAdded`. could you explain the difference between that and `.observe(DataEventType.childAdded`? – Vincenzo Mar 22 '19 at 23:18

0 Answers0