swift - 在 Swift 中从 Firebase 快照获取值

标签 swift firebase firebase-realtime-database

我已成功从 Firebase 获取数据,但无法将其推送到数组中使用。我的数据库如下:

users
    -Wc1EtcYzZSMPCtWZ8wRb8RzNXqg2
        -email : "mike@gmail.com"
        -lists
            -LJiezOzfDrqmd-hnoH-
                -owner: Wc1EtcYzZSMPCtWZ8wRb8RzNXqg2
            -LJif-UgPgbdGSHYgjY6
                -owner: Wc1EtcYzZSMPCtWZ8wRb8RzNXqg2

shopping-lists
    -LJh6sdBJtBCM7DwxPRy
        -name: "weekly shopping"
        -owner: "mike@gmail.com"

登录后我有一个主页,如果存在的话,会在表格上显示现有的购物 list 。在 viewDidLoad() 上,我从用户那里获取购物 list ID,并使用这些 ID 作为引用,从购物 list 中获取详细信息。

但是,我无法设法将这些数据保存到数组中,因为它在关闭后会被删除。我怎样才能以干净的方式做到这一点?

override func viewDidLoad() {
        super.viewDidLoad()

        SVProgressHUD.show()
        tableView.allowsMultipleSelectionDuringEditing = false

        // Sets user variable - must have
        Auth.auth().addStateDidChangeListener { auth, user in

            guard let user = user else { return }
            self.user = User(authData: user)

            // If new user, write into Firebase
            self.usersRef.observeSingleEvent(of: .value, with: { snapshot in
                if !snapshot.hasChild(self.user.uid) {
                    self.usersRef.child(user.uid).setValue(["email": user.email!])
                }
            })

            // Get shopping lists data from "users/lists"
            self.usersRef.child(user.uid).child("lists").observe(.value, with: { snapshot in

                // Get list IDs
                if snapshot.exists() {
                    if let result = snapshot.children.allObjects as? [DataSnapshot] {
                        for child in result {
                            self.listNames.append(child.key)
                        }
                    }
                }

                // Use list IDs - to get details
                for item in self.listNames {
                    let itemRef = self.shoppingListsRef.child(item)
                    itemRef.observeSingleEvent(of: .childAdded, with: { (snapshot) in
                        if let value = snapshot.value as? [String: Any] {
                            let name = value["name"] as? String ?? ""
                            let owner = value["owner"] as? String ?? ""

                            let shoppingList = ShoppingList(name: name, owner: owner)
                            self.items.append(shoppingList)
                        }
                    })
                }
            })

            self.tableView.reloadData()
            SVProgressHUD.dismiss()
        }
    }

最佳答案

(这个问题有点不清楚,所以这个答案的几个部分涵盖了所有可能性。这是 Swift 4,Firebase 4/5)

你真的不需要在这里查询,因为你知道你想要哪些节点的键,并且它们将始终按照你的 listNames 数组的顺序读取。这假定 self.listNames 是您要读入的键。

for item in listNames {
    let itemRef = shoppingListsRef.child(item)
    itemRef.observe(.value, with: { (snapshot) in
        if let value = snapshot.value as? [String: Any] {
            let name = value["name"] as? String ?? ""
            let owner = value["owner"] as? String ?? ""
            print(name, owner)
        }
    })
}

通常,当您在节点内搜索某些内容时会使用查询 - 例如,如果您要查找包含子名称“每周购物”的节点。除此之外,坚持直接读取节点,因为它更快并且开销更少。继续阅读...

我还删除了旧的 NSDictionary 并使用 Swift [String: Any] 并修改了错误检查

然而,真正的问题是通过 .value 读取具有 .observe 的节点。请记住,.value 读取节点的所有子节点,然后需要迭代子节点以获取每个单独的 DataSnapshot。此外, .observe 在节点上留下一个观察者,通知应用程序发生变化,我认为你不想要。所以这将回答发布的问题,(并且需要更好的错误检查)

for item in listNames {
    let queryRef = shoppingListsRef
        .queryOrdered(byChild: "name")
        .queryEqual(toValue: item)

    queryRef.observe(.value, with: { (snapshot) in
        for child in snapshot.children { //even though there is only 1 child
            let snap = child as! DataSnapshot
            let dict = snap.value as! [String: Any]
            let name = dict["name"] as? String ?? ""
            let owner = dict["owner"] as? String ?? ""
            print(name, owner)
        }
    })
}

答案...

这可能是你想要的更多...

for item in listNames {
    let queryRef = shoppingListsRef
        .queryOrdered(byChild: "name")
        .queryEqual(toValue: item)

    queryRef.observeSingleEvent(of: .childAdded, with: { snapshot in
        let dict = snapshot.value as! [String: Any]
        let name = dict["name"] as? String ?? ""
        let owner = dict["owner"] as? String ?? ""
        print(name, owner)
    })
}

请注意 .childAdded 而不是 .value,它将快照呈现为单个 DataSnapshot 并且不需要迭代,而 .observeSingleEvent 不会让观察者附加到每个节点。

编辑

根据附加信息,最好也将结构更改为此

shopping-lists
    -LJh6sdBJtBCM7DwxPRy
        -name: "weekly shopping"
        -uid: "Wc1EtcYzZSMPCtWZ8wRb8RzNXqg2"

然后当用户登录时,只需在购物 list 节点中查询属于他们的任何 uid。

关于swift - 在 Swift 中从 Firebase 快照获取值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51807891/

相关文章:

ios - Swift 使用 realm.add() 或 realm.create() 将大量数据写入 Realm

swift 1.2 : Method does not override any method from its superclass

c# - Unity+Firebase-数据库[错误] WebSocket : ws_0 - could not connect

java - 如何在 onDataChange + Glide 循环 "for"继续之前等待图像加载?

ios - 滚动父 View 的 CollectionView 以在模式关闭之前显示单元格

javascript - 在没有 Firebase 的情况下使用 Webhook

android - 允许在发送指定数据后更新某些值的 Firebase 规则

node.js - angularfire2安装和设置期间出现错误

ios - Firebase iOS Swift fatal error : NSArray element failed to match the Swift Array Element type

ios - 引用 TableView 单元格时出错