如果未显式调用该函数,则不会调用.childAdded观察器.斯威夫特4 [英] .childAdded observer doesn't get called If the function is not called explicitly. Swift 4

查看:59
本文介绍了如果未显式调用该函数,则不会调用.childAdded观察器.斯威夫特4的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个函数,该函数应侦听Firebase节点并在发布新帖子时获取快照,但是该函数一点也不会感到烦恼,就像观察者.observe(DataEventType.childAdded, with: { (snapshot) in在其中看不到新帖子一样.节点.我检查了一下,确实在Firebase中实时注册了新帖子.我应该调用该函数还是应该由观察者执行? 继承人的完整功能:

I have a function that should listen to a Firebase node and get a snapshot of new posts when they get posted, but the function is not getting galled at all, as if the observer .observe(DataEventType.childAdded, with: { (snapshot) in didn't see new posts in the node. I checked and new posts are indeed registered in real time in Firebase. Should I call the function or is the observer that should do it? Heres the complete function:

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


    }

推荐答案

让我们尝试通过几个链接和一个代码示例来回答这个问题,而不是冗长的讨论.

Instead of a lengthy discussion in comments let's try to answer this with a couple of links and a code example.

但是,首先,您仅应在视图可见时同步数据,并在每次视图变为可见时调用viewWillAppear方法,因此这是添加观察者的好地方.最好在不需要观察者时删除观察者(节省带宽),这可以使用viewDidDisappear中的firebase句柄来完成.这是一篇过时的文章,但读得很好

First though, you should only synchronize data when a view is visible and the viewWillAppear method is called each time the view becomes visible, so that's a good place to add observers. It's also good practice to remove observers when you don't need them (saves bandwidth) and that can be done using a firebase handle in the viewDidDisappear. Here's a slightly dated article but a great read

UIViewController和Firebase的最佳做法

并举一个很好的例子,请参阅此问题的答案

and for a great example, see the answer to this question

Firebase:何时快速调用removeObserverWithHandle

要解决其余的问题(请注意,我将其简短表示,以便不包括使用手柄)

To address the rest of the question (note I am keeping this short so I didn't include using handles)

我有一堂课来存储警报

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

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

然后是一个用于存储所有警报的var类别数组

and then a class var array to store all of the alerts

var alertArray = [AlertClass]()

然后我们从viewWillAppear函数添加观察者

and then we add our observers from the viewWillAppear function

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

将三个观察者添加到引用的节点; .childAdded,.childChanged和.childRemoved.请记住,.childAdded将在ref节点中的节点上进行迭代,并在调用viewWillAppear时填​​充我们的dataSource,因此我们需要重置"数组,以免意外在现有数据之上加载数据.您的用例可能会有所不同,因此请相应地编写代码.

which adds three observers to the referenced node; .childAdded, .childChanged, and .childRemoved. Keep in mind that .childAdded will iterate over the nodes in the ref node and populate our dataSource any time viewWillAppear is called, so we need to 'reset' the array so we don't accidentally load data on top of the existing data. Your use case may differ so code accordingly.

下面是添加观察者并在发生任何更改时打印数组的代码.

Here's the code to add the observers and prints the array any time there's a change.

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

作为旁注...

如果通过childAdded填充tableView数据源,则您可能想知道如何做到这一点,而无需重复调用tableView.reloadData,这可能会导致闪烁.通过利用在.childAdded之后调用.value事件的事实,可以做到这一点.查看我对这个问题的回答作为示例.

If you're populating a tableView dataSource via the childAdded you may be wondering how to do that without calling tableView.reloadData repeatedly, which may cause flicker. There's a techniqure for doing that by leveraging the fact that .value events are called after .childAdded. See my answer to this question for an example.

这篇关于如果未显式调用该函数,则不会调用.childAdded观察器.斯威夫特4的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆