在Swift中从Firebase快照获取值

时间:2018-08-12 10:19:48

标签: 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"

登录后我有一个主页,该主页在表上显示现有的购物清单(如果存在)。在viewDidLoad()上,我从用户那里获得购物清单ID,并使用这些ID作为参考来从购物清单中获取详细信息。

但是,我无法将这些数据保存到数组中,因为关闭后它们将被删除。我怎样才能做到这一点?

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()
        }
    }

1 个答案:

答案 0 :(得分:1)

(这个问题有点不清楚,所以这个答案的几个部分涵盖了所有可能。这是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的节点。请记住,.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"

,然后当用户登录时,只需在购物清单节点中查询自己的任何uid。