Наблюдатель .childAdded не вызывается, если функция не вызывается явно.Swift 4 - PullRequest
0 голосов
/ 02 марта 2019

У меня есть функция, которая должна прослушивать узел Firebase и получать снимок новых сообщений, когда они публикуются, но функция вообще не отключается, как если бы наблюдатель .observe(DataEventType.childAdded, with: { (snapshot) in не видел новых сообщений вузел.Я проверил, и новые сообщения действительно зарегистрированы в реальном времени в Firebase.Должен ли я вызвать функцию или наблюдатель должен это сделать?Вот полная функция:

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

        print("                     MapArray.alertNotificationCoordinatesArray before  getNewerAlerts snapshot is: \(MapArray.alertNotificationCoordinatesArray)")
        print("                     self.userAlertNotificationArray before getNewerAlerts snapshot is: \(self.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(DataEventType.childAdded, with: { (snapshot) in
            print("         snapshot is: \(snapshot)")
            guard let data = snapshot.value as? [String:[String:String]] else { return }
            guard let firebaseKey = snapshot.key as? String else { return }
            //                let date = data!["Date"]
            //                let time = data!["Time"]
            data.values.forEach {
                let dataLatitude = $0["Latitude"]!
                let dataLongitude = $0["Longitude"]!

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

                //            print("Firebase alerts posts retrieved")

                let userAlertAnnotation = UserAlert(type: type, coordinate: recombinedCoordinate, firebaseKey: firebaseKey, title: type,id: id!)

                self.mapView.addAnnotation(userAlertAnnotation)
                self.userAlertNotificationArray.append(userAlertAnnotation)
                MapArray.alertNotificationCoordinatesArray.append(recombinedCoordinate)
            }
            print("                 MapArray.alertNotificationCoordinatesArray after getNewerAlerts snapshot is: \(MapArray.alertNotificationCoordinatesArray)")
            print("                     self.userAlertNotificationArray after getNewerAlerts snapshot is: \(self.userAlertNotificationArray)")
            setCompletion(true)
        })

    }

Большое спасибо.

РЕДАКТИРОВАТЬ Переписанная функция:

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
        ref?.child("Continent").child("Europe").child("Country").child("Italy").child("Region").child("Emilia-Romagna").child("City").child("Bologna").child("Community").child("Alert Notifications").observe(DataEventType.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
        ref?.child("Continent").child("Europe").child("Country").child("Italy").child("Region").child("Emilia-Romagna").child("City").child("Bologna").child("Community").child("Alert Notifications").observe(DataEventType.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)
        })


    }

1 Ответ

0 голосов
/ 03 марта 2019

Вместо длинного обсуждения в комментариях давайте попробуем ответить на это парой ссылок и примером кода.

Во-первых, синхронизировать данные следует только тогда, когда представление является видимым и вызывается метод viewWillAppear.каждый раз вид становится видимым, так что это хорошее место для добавления наблюдателей.Также хорошей практикой является удаление наблюдателей, когда они вам не нужны (экономит пропускную способность), и это можно сделать с помощью маркера firebase в viewDidDisappear.Вот немного устаревшая статья, но отличное чтение

Лучшие практики для UIViewController и Firebase

и отличный пример, см. Ответ на этот вопрос

Firebase: когда вызывать removeObserverWithHandle в swift

Для решения остальной части вопроса (обратите внимание, я держу это сокращение, поэтому я не включил использование ручек)

У меня есть класс для хранения предупреждений

class AlertClass {
    var node_key = ""
    var msg = ""

    init(aKey: String, aMsg: String) {
        self.node_key = aKey
        self.msg = aMsg
    }
}

, а затем массив var класса для хранения всех предупреждений

var alertArray = [AlertClass]()

, а затем мы добавляем наших наблюдателей из функции viewWillAppear

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    self.addObservers()
}

, который добавляет трех наблюдателей к указанному узлу;.childAdded, .childChanged и .childRemoved.Имейте в виду, что .childAdded будет перебирать узлы в узле ref и заполнять наш источник данных каждый раз, когда вызывается viewWillAppear, поэтому нам нужно «сбросить» массив, чтобы мы случайно не загрузили данные поверх существующих данных.Ваш вариант использования может отличаться, поэтому используйте соответствующий код.

Вот код для добавления наблюдателей и печати массива в любое время, когда есть изменение.

func addObservers() {
    let ref = self.ref.child("Continent").child("Europe").child("Country").child("Italy").child("Region").child("Emilia-Romagna").child("City").child("Bologna").child("Community").child("Alert Notifications")
    self.alertArray = []
    ref.observe(.childAdded, with: { (snapshot) in
        let key = snapshot.key
        let msg = snapshot.childSnapshot(forPath: "msg").value as! String
        let aAlert = AlertClass(aKey: key, aMsg: msg)
        self.alertArray.append(aAlert) //append the new alert
        self.showAlertArray() //this is called for every child
    })

    ref.observe(.childChanged, with: { (snapshot) in
        let key = snapshot.key
        let msg = snapshot.childSnapshot(forPath: "msg").value as! String
        if let foundAlert = self.alertArray.first(where: { $0.node_key == key } ) {
            foundAlert.msg = msg //update the alert msg
            self.showAlertArray()
        }
    })

    ref.observe(.childRemoved, with: { (snapshot) in
        let key = snapshot.key
        self.alertArray.removeAll(where: { $0.node_key == key }) //remove the alert
        self.showAlertArray()
    })
}

func showAlertArray() {
    for alert in self.alertArray {
        print(alert.node_key, alert.msg)
    }
}

и в качестве примечания ...

Если вы заполняете источник данных tableView через childAdded, вам может быть интересно, как это сделать без повторного вызова tableView.reloadData, что может вызвать мерцание.Есть способ сделать это, используя тот факт, что события .value вызываются после .childAdded.См. Мой ответ на этот вопрос для примера.

...