如何从 Firebase 快照解析单个字典?

How to Parse a Single Dictionary from Firebase Snapshot?

我的代码是:

_ = DataService.ds.REF_POSTS.child(key!).observe(.value, with: { (snapshot) in  

                })

key 等于 post 密钥 (-Kef2J6vJBCjHGYjSlkI)。我只想一次检索一个元素。
child下只有1个字典:

我需要根据其中的内容创建字典。但是,当我实现常规算法时:

_ = DataService.ds.REF_POSTS.child(key!).observe(.value, with: { (snapshot) in  

if let snapshot = snapshot.children.allObjects as? [FIRDataSnapshot] {
                for snap in snapshot {
                    print("Zhenya: here is the snap: \(snap)")
                    if let postDict = snap.value as? Dictionary<String, AnyObject> {
                        let key = snap.key
                        let post = Post(postKey: key, postData: postDict)
                        self.posts.append(post)
                    } else {
                        print("Zhenya: failed to convert")
                    }
                }
            }
                })

'snap' 打印字典本身的元素,而不是整个字典。所以它总是在下一行转换失败。


忍者奖励:

如果您能提出更好的架构,我将不胜感激。 从 FB 中一个一个地检索 posts 似乎会大大降低性能。
之所以是'one by one',是因为这个post是用户GeoFire规范的结果。附近 post 的 Geofire returns 键。 我想根据返回的键过滤 Firebase 的 posts 主分支,但没有办法做到这一点 - 只能一个接一个地加载(.orderByChild - 不会 returns posts,而是订购所有 posts。如果您知道它如何帮助我,请提供建议)

这是您问题中提供的代码:

_ = DataService.ds.REF_POSTS.child(key!).observe(.value, with: { (snapshot) in  

if let snapshot = snapshot.children.allObjects as? [FIRDataSnapshot] {
        for snap in snapshot {
            print("Zhenya: here is the snap: \(snap)")
            if let postDict = snap.value as? Dictionary<String, AnyObject> {
                let key = snap.key
                let post = Post(postKey: key, postData: postDict)
                self.posts.append(post)
            } else {
                print("Zhenya: failed to convert")
            }
        }
    }
})

让我们来看看这里发生了什么。

第一行是使用 .value 方法在 Firebase 中观察 posts/$post-id.value 方法 returns 您在 FIRDataSnapshot 中提供的引用,其中 snapshot.key 是 child 的名称, snapshot.value 是包含的字典它 children.

因此,DataService.ds.REF_POSTS.child(key!).observe(.value, with: { (snapshot) in ... }) 中的 snapshot 应该如下所示:

$post-id
    imageUrl: http://...
    likes: 0
    userKey: ...

但是在下一行中,您使用本地定义重新定义了 snapshot。这就是为什么你得到 post 的 children 的原因,因为你明确地这样定义它:

if let snapshot = snapshot.children.allObjects as? [FIRDataSnapshot] { ... }

如果删除它,您应该会看到所需的行为。


那么你真正应该做什么?好吧,我不喜欢使用 .value,因为它有一些缺点:

  • 它下载请求的整个节点。如果您弄乱了对大节点的引用(即 ref/users),.value 操作很容易需要几秒钟才能看到 any 数据。

  • 只调用一次。如果你的数据库是静态的,这很好,但是谁的数据库是静态的?

这就是为什么我更喜欢将 .childAdded 用于 post、消息等。它一次 returns 一个节点,这意味着您可以填充一个列表随着新数据的可用而逐步进行。使用一些聪明的 UI 函数(例如 tableView.insertRows(...) 你可以相当顺利地显示大量数据而无需等待结果。我相信它也支持分页,你可以在其中以 10 个为一组获取它们,例如. Here 是关于如何开始使用 .childAdded 充分利用大型数据列表的快速入门。