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

时间:2017-03-29 20:47:32

标签: ios swift firebase geofire

我的代码是:

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

                })

key等于后置密钥(-Kef2J6vJBCjHGYjSlkI)。我想一次只检索一个元素 那个孩子下面只有一本字典:

enter image description here

我需要从中创建一个字典。但是,当我实现常规算法时:

_ = 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逐个检索帖子会大大降低性能 它是“一个接一个”的原因是这个帖子是用户的GeoFire规范的结果。 Geofire会将密钥返回到附近的帖子。 我想根据返回的密钥过滤Firebase的主要帖子分支,但是没有办法做到这一点 - 只能逐个加载(.orderByChild - 不返回帖子,而是命令所有帖子。如果你是知道它可以帮助我,请建议)

1 个答案:

答案 0 :(得分:2)

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

_ = 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")
            }
        }
    }
})

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

第一行是使用posts/$post-id方法在Firebase中观察.value.value方法会返回您在FIRDataSnapshot中提供的引用,其中snapshot.key是子名称,snapshot.value是包含其子项的字典。

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

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

但是在下一行中,您使用本地定义重新定义snapshot。这就是为什么你要得到帖子的孩子,因为你明确地定义它:

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

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

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

  • 下载请求的整个节点。如果你搞砸了大型节点(即ref / users)的引用,那么.value操作很容易在你看到任何数据之前需要几秒钟。

    < / LI>
  • 只调用一次。如果您的数据库是静态的,但其数据库是静态的,那么这很好吗?

这就是为什么我更喜欢将.childAdded用于帖子,消息等等。它一次返回一个节点,这意味着您可以在新数据可用时逐步填充列表。使用一些聪明的UI功能(例如tableView.insertRows(...),您可以非常顺利地显示大型数据列表而无需等待结果。我相信它也支持分页,例如,您可以在10个批次中获取它们。{{3是一个快速入门,介绍如何开始使用.childAdded来充分利用大型数据列表。