如果未显式调用该函数,则不会调用.childAdded观察者。斯威夫特4

时间:2019-03-02 11:53:21

标签: swift firebase firebase-realtime-database observers

我有一个函数,该函数应侦听Firebase节点并在发布新帖子时获取它们的快照,但是该功能根本不会让人感到烦恼,好像观察者Bird buzzard = new Bird("Buzzard", "Buteo buteo", (short) 51, (short) 57, 550, 1300, EnumSet.of(AnimalColour.BROWN) ... // pass in other parameters ); 看不到新帖子一样在节点中发布。我检查了一下,确实在Firebase中实时注册了新帖子。我应该调用该函数还是应该由观察者执行? 继承人的完整功能:

.observe(DataEventType.childAdded, with: { (snapshot) in

非常感谢您。

编辑 重写功能:

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

    }

1 个答案:

答案 0 :(得分:1)

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

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

Best Practices for UIViewController and Firebase

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

Firebase: when to call removeObserverWithHandle in 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时填​​充我们的dataSource,因此我们需要“重置”数组,以免意外在现有数据之上加载数据。您的用例可能会有所不同,因此请相应编码。

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

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事件的事实,可以做到这一点。有关示例,请参见我对this question的回答。