.oberserve(.childAdded)产生错误而.observeSingleEvent(of:。value)则不然

时间:2017-09-14 08:54:30

标签: swift xcode firebase

现在我有.observeSingleEvent(of: .value)将我的所有注释加载到地图上:

func loadAnnotations() {

    if let uid = Auth.auth().currentUser?.uid {
        uidRef.child(uid).child("annotations").observeSingleEvent(of: .value, with: { (snapshot) in

            for item in snapshot.children {

                // annotationListItem is a struct I created
                let annotationItem = AnnotationListItem(snapshot: item as! DataSnapshot)

                let doubleLatitude = Double(annotationItem.mapViewLatitude!)
                let doubleLongitude = Double(annotationItem.mapViewLongitude!)
                let coordinate = CLLocationCoordinate2DMake(doubleLatitude!, doubleLongitude!)

                let annotation = MKPointAnnotation()
                annotation.coordinate = coordinate
                annotation.title = annotationItem.annotationTitle
                annotation.subtitle = annotationItem.annotationSubtitle
                self.mapView.addAnnotation(annotation)

            }
        }, withCancel: nil)

    }
}

现在我希望每次用户添加新注释时都会更新地图,因此我使用.observe(.childAdded)

输入完全相同的代码
func annotationChildAdded() {

    if let uid = Auth.auth().currentUser?.uid {
        uidRef.child(uid).child("annotations").observe(.childAdded, with: { (snapshot) in

            for item in snapshot.children {
                let annotationItem = AnnotationListItem(snapshot: item as! DataSnapshot)

                let doubleLatitude = Double(annotationItem.mapViewLatitude!)
                let doubleLongitude = Double(annotationItem.mapViewLongitude!)
                let coordinate = CLLocationCoordinate2DMake(doubleLatitude!, doubleLongitude!)

                let annotation = MKPointAnnotation()
                annotation.coordinate = coordinate
                annotation.title = annotationItem.annotationTitle
                annotation.subtitle = annotationItem.annotationSubtitle
                self.mapView.addAnnotation(annotation)
            }

        }, withCancel: nil)
    }
}

我收到错误:

无法将类型'__NSCFString'(0x1060b84f0)的值转换为'NSDictionary'(0x1060b92d8)。 打印snapshotValue的描述: ([String:AnyObject])snapshotValue =变量不可用>

如何解决此问题?

更新

.observe(.value)有效。但我仍然想知道为什么.childAdded没有

1 个答案:

答案 0 :(得分:0)

这里的问题是.observeSingleEvent(of: .value).observe(.childAdded)不会返回相同的内容。

当你致电.observe(.value)时,它会在事件发生时返回包含所有内容的整个节点。

但是,当您使用.observe(.childAdded)时,它将仅返回添加到指定路径的内容(即添加的子项)。

您可以通过在两种方法中执行print(snapshot)来看到,您将很容易看到差异。

因此,要使用.childAdded访问您的数据,您不需要像使用.observeSingleEvent(of:。value)一样遍历所有子项。相反,你会这样做:

        guard let uid = Auth.auth().currentUser?.uid else {
           return 
        }

        uidRef.child(uid).child("annotations").observe(.childAdded, with: { (snapshot) in

                let annotationItem = AnnotationListItem(snapshot: item as! DataSnapshot)

                let doubleLatitude = Double(annotationItem.mapViewLatitude!)
                let doubleLongitude = Double(annotationItem.mapViewLongitude!)
                let coordinate = CLLocationCoordinate2DMake(doubleLatitude!, doubleLongitude!)

                let annotation = MKPointAnnotation()
                annotation.coordinate = coordinate
                annotation.title = annotationItem.annotationTitle
                annotation.subtitle = annotationItem.annotationSubtitle
                self.mapView.addAnnotation(annotation)
            }

        })

另外,我不建议您像item as! DataSnapshot那样强制推送您的项目,因为如果您错过了数据库中的内容,应用程序就会崩溃。

相反,我会这样做,使用保护声明:

guard let uid = Auth.auth().currentUser?.uid else {
     return 
}

uidRef.child(uid).child("annotations").observe(.childAdded, with: { [weak self] (snapshot) in

        let annotationKey = snapshot.key

        guard let longitude = snapshot.childSnapshot(forPath: "longitude").value as? NSNumber else { return }

        guard let latitude = snapshot.childSnapshot(forPath: "latitude").value as? NSNumber else { return }

        guard let title = snapshot.childSnapshot(forPath: "title").value as? String else { return }

        // Here it really depends on how your database look like.

        // ...

        // Create your annotation item using the values from the snapshot :

        let annotation = AnnotationListItem(id: annotationKey, title: title, longitude: longitue, latitude: latitude)

        // Finally add the data to an array :

        self?.annotationsArray.append(annotation)

        // Or directly to your mapView :

        self?.mapView.addAnnotation(annotation)

})

请告诉我是否有帮助; D

<强>更新

例如,假设您的数据库中最初有3个子节点。它会做那样的事情:

initial:观察者被调用:

你得到孩子1

你得到孩子2

你得到孩子3

现在,如果添加了另一个孩子:

新孩子:观察者被召唤:

你得到孩子4

等。