如果未显式调用该函数,则不会调用 .childAdded 观察者。 Swift 4
.childAdded observer doesn't get called If the function is not called explicitly. Swift 4
我有一个函数应该监听 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 = [=11=]["Latitude"]!
let dataLongitude = [=11=]["Longitude"]!
let type = [=11=]["Description"]!
let id = Int([=11=]["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: { ([=12=].firebaseKey == firebaseKey) }) //remove the alert
MapArray.alertNotificationCoordinatesArray.removeAll(where: { ([=12=].latitude == recombinedCoordinate.latitude && [=12=].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)
})
}
与其在评论中进行冗长的讨论,不如尝试通过几个链接和一个代码示例来回答这个问题。
首先,您应该只在视图可见时同步数据,并且每次视图变为可见时都会调用 viewWillAppear 方法,因此这是添加观察者的好地方。在不需要观察者时移除观察者(节省带宽)也是一种很好的做法,这可以使用 viewDidDisappear 中的 firebase 句柄来完成。这是一篇略显过时的文章,但值得一读
Best Practices for UIViewController and Firebase
关于一个很好的例子,请参阅这个问题的答案
Firebase: when to call removeObserverWithHandle in swift
解决问题的其余部分(注意我保持简短,所以我没有包括使用句柄)
我有一个 class 来存储警报
class AlertClass {
var node_key = ""
var msg = ""
init(aKey: String, aMsg: String) {
self.node_key = aKey
self.msg = aMsg
}
}
然后是一个 class var 数组来存储所有警报
var alertArray = [AlertClass]()
然后我们从 viewWillAppear 函数中添加我们的观察者
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.addObservers()
}
将三个观察者添加到引用节点; .childAdded、.childChanged 和 .childRemoved。请记住,.childAdded 将遍历 ref 节点中的节点并在调用 viewWillAppear 时填充我们的数据源,因此我们需要 'reset' 数组,这样我们就不会意外地在现有数据之上加载数据.您的用例可能有所不同,因此请相应地编写代码。
这是添加观察者并在数组发生变化时打印数组的代码。
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: { [=13=].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: { [=13=].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 的情况下执行此操作,这可能会导致闪烁。有一种技术可以利用 .value 事件在 .childAdded 之后调用这一事实来做到这一点。例如,请参阅我对 this question 的回答。
我有一个函数应该监听 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 = [=11=]["Latitude"]!
let dataLongitude = [=11=]["Longitude"]!
let type = [=11=]["Description"]!
let id = Int([=11=]["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: { ([=12=].firebaseKey == firebaseKey) }) //remove the alert
MapArray.alertNotificationCoordinatesArray.removeAll(where: { ([=12=].latitude == recombinedCoordinate.latitude && [=12=].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)
})
}
与其在评论中进行冗长的讨论,不如尝试通过几个链接和一个代码示例来回答这个问题。
首先,您应该只在视图可见时同步数据,并且每次视图变为可见时都会调用 viewWillAppear 方法,因此这是添加观察者的好地方。在不需要观察者时移除观察者(节省带宽)也是一种很好的做法,这可以使用 viewDidDisappear 中的 firebase 句柄来完成。这是一篇略显过时的文章,但值得一读
Best Practices for UIViewController and Firebase
关于一个很好的例子,请参阅这个问题的答案
Firebase: when to call removeObserverWithHandle in swift
解决问题的其余部分(注意我保持简短,所以我没有包括使用句柄)
我有一个 class 来存储警报
class AlertClass {
var node_key = ""
var msg = ""
init(aKey: String, aMsg: String) {
self.node_key = aKey
self.msg = aMsg
}
}
然后是一个 class var 数组来存储所有警报
var alertArray = [AlertClass]()
然后我们从 viewWillAppear 函数中添加我们的观察者
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.addObservers()
}
将三个观察者添加到引用节点; .childAdded、.childChanged 和 .childRemoved。请记住,.childAdded 将遍历 ref 节点中的节点并在调用 viewWillAppear 时填充我们的数据源,因此我们需要 'reset' 数组,这样我们就不会意外地在现有数据之上加载数据.您的用例可能有所不同,因此请相应地编写代码。
这是添加观察者并在数组发生变化时打印数组的代码。
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: { [=13=].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: { [=13=].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 的情况下执行此操作,这可能会导致闪烁。有一种技术可以利用 .value 事件在 .childAdded 之后调用这一事实来做到这一点。例如,请参阅我对 this question 的回答。