swift - .oberve(.childAdded) 产生错误,而 .observeSingleEvent(: . 值)不是

标签 swift xcode firebase

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

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)

    }
}

现在我希望 map 在每次用户添加新注释时更新,所以我输入了完全相同的代码,但使用了 .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 没有

最佳答案

这里的问题是 .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 语句:

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 个子节点。它会做类似的事情:

初始:观察者被调用:

你得到 child 1

你得到 child 2

你得到 child 3

现在,如果添加另一个 child :

新 child :观察者被调用:

你得到 child 4

等..

关于swift - .oberve(.childAdded) 产生错误,而 .observeSingleEvent(: . 值)不是,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46214627/

相关文章:

c++ - thread_local 的替代方法,用于在 OSX 上调用遗留 C 代码

iphone - FB 返回崩溃应用程序 xcode ios iphone

java - Android Firebase 如何处理实时服务器到本地数据库的连接

javascript - 当 Firebase 数据不是 "undefined"时

swift - 尝试使用 Alamofire 缓存但没有结果

c++ - SDL_ttf 框架不会在 xCode 上运行,给出错误链接器命令失败,退出代码为 1

arrays - 设置用户位于 UIPageControl 最后一页时登录/注册按钮的可见性

iOS Firebase 推送通知 : How To Give Firebase User's Device Token And Send Notification

ios - 无法快速将具有 nil 值的字典添加到数组中

ios - 前一天凌晨 4 点的日期