Firebase不会把我的价值发送给我的变量

时间:2018-12-29 17:21:40

标签: swift firebase firebase-realtime-database

我有一个代码,通常应该从Firebase向我返回一个值。

我的Firebase结构是:

Experience{
    UserId{
        LDG_DAY: "4"
        LDG_NIGHT: "0"
        APCH_IFR: "0"
    }
}

我的代码是:

func getUserExp(){
    let ref = Database.database().reference()
    let userID = Auth.auth().currentUser?.uid
    let Date = self.flightDate.text
 ref.child("Experience")/*.child(userID!)*/.observeSingleEvent(of: .value) {(snapshot) in
            if snapshot.hasChild(userID!){
                let value = snapshot.value as? NSDictionary


                let ldg_day = value?["LDG_DAY"] as? String ?? "123"
                let ldg_night = value?["LDG_NIGHT"] as? String ?? "0"
                let apch_ifr = value?["APCH_IFR"] as? String ?? "0"


                self.intLdgDay = Int(ldg_day)!
                self.intLdgNight = Int(ldg_night)!
                self.intApchIfr = Int(apch_ifr)!

                print("string = \(ldg_day) int = \(self.intLdgDay)")



            }
        }
}

现在代码无法按照我的意愿运行...实际上,我的代码返回了基本的as? String ?? "123"值,但是snapshot.value从firebase中获得了很好的价值... 怎么了 ?我将此代码用于应用程序的许多其他部分,对此没有问题吗?

感谢您的帮助

2 个答案:

答案 0 :(得分:1)

我相信您想在尝试读取子数据之前确保该节点存在。

注意:

我看到读取路径已注释掉uid,因此尚不清楚您是打算读取一个用户(保留uid)还是要一次加载每个用户(数千个)。该答案假定您仅打算阅读该特定用户节点。如果您打算一次读取所有用户节点,请参阅@Callam答案。

您现在使用的代码正在使用snapshot.hasChild,该文件在节点内查找以查看子代,用户uid是否存在,并且不存在,因此代码将始终失败。

if snapshot.hasChild(userID!)

我认为您想要做的是使用snapshot.exists来确保它是有效的节点,然后再进行读取。这是代码:

let experienceRef = self.ref.child("Experience")
let usersExpRef = experienceRef.child(uid)
usersExpRef.observeSingleEvent(of: .value) { snapshot in
    if snapshot.exists() {
        let value = snapshot.value as! [String: Any]
        let ldg_day = value["LDG_DAY"] as? String ?? "123"
        print("string = \(ldg_day)")
    } else {
        print("the \(uid) node does not exist")
    }
}

我还建议在尝试使用它们之前安全地解开选项,因为它们可能为零,这会使您的代码崩溃。

guard let thisUser = Auth.auth().currentUser else { return }
let uid = thisUser.uid

请注意,我还用它的Swifty副本[String:Any]替换了旧的objc NSDictionary

答案 1 :(得分:0)

假设您的结构是从根开始的,并且Experience包含多个用户ID,则由于/*.child(userID!)*/已被注释掉,因此您的代码当前正在观察所有用户ID的值。

因此,您正在请求每个用户的体验,并在客户端上检查当前用户是否以孩子的身份存在–如果当前用户的ID位于Experience/$uid,则将成功。

ref.child("Experience")/*.child(userID!)*/.observeSingleEvent(of: .value) { (snapshot) in
    if snapshot.hasChild(userID!) {
        let value = snapshot.value as? NSDictionary

现在我们有了一个包含所有“体验”的快照,并且我们已经确认它具有当前用户ID的子代-我们需要获取那个子代并将其值转换为字典

let value = snapshot.childSnapshot(forPath: userID).value as? NSDictionary

这可以解决问题,但显然,我们不想在单个用户的设备上下载所有体验,而且他们甚至都不应该具有请求该参考位置的权限。


因此,如果您取消注释.child(userID!),快照将只是一个体验,因此snapshot.hasChild(userID!)将失败。相反,您可以使用snapshot.exists()和/或条件转换来确定userID的快照是否存在和/或可转换。

func getUserExp() {
    let ref = Database.database().reference()
    let userID = Auth.auth().currentUser?.uid
    let Date = self.flightDate.text

    ref.child("Experience").child(userID!).observeSingleEvent(of: .value) { snapshot in
        if snapshot.exists() {
            let value = snapshot.value as? [String:String]

            let ldg_day = value?["LDG_DAY"] ?? "123"
            let ldg_night = value?["LDG_NIGHT"] ?? "0"
            let apch_ifr = value?["APCH_IFR"] ?? "0"

            self?.intLdgDay = Int(ldg_day)!
            self?.intLdgNight = Int(ldg_night)!
            self?.intApchIfr = Int(apch_ifr)!

            print("string = \(ldg_day) int = \(self.intLdgDay)")
        } else {
            print("experience for \(snapshot.key) doesn't exist")
        }
    }
}

您可以使用结构和扩展名对其进行清理。

// Experience.swift

struct Experience {
    var ldg_day: String
    var ldg_night: String
    var apch_ifr: String
}

extension Experience {
    static var currentUserRef: DatabaseReference? {
        return Auth.auth().currentUser.flatMap {
            return Database.database().reference(withPath: "Experience/\($0.uid)")
        }
    }

    init?(snapshot: DataSnapshot) {
        guard snapshot.exists() else { return nil }

        let value = snapshot.value as? [String:String]

        self.ldg_day = value?["LDG_DAY"] ?? "123"
        self.ldg_night = value?["LDG_NIGHT"] ?? "0"
        self.apch_ifr = value?["APCH_IFR"] ?? "0"
    }
}

Etvoilà,

func getUserExp() {
    Experience.currentUserRef?.observeSingleEvent(of: .value, with: { [weak self] in
        if let experience = Experience(snapshot: $0) {
            self?.intLdgDay = Int(experience.ldg_day)!
            self?.intLdgNight = Int(experience.ldg_night)!
            self?.intApchIfr = Int(experience.apch_ifr)!

            print("string = \(experience.ldg_day) int = \(self.intLdgDay)")
        } else {
            print("experience for \($0.key) doesn't exist")
        }
    })
}