如果Firebase值为nil,如何定义辅助值

时间:2018-04-28 04:03:40

标签: ios firebase

在我的应用程序中,我有一个用于返回电子邮件的功能,但当然我的beta测试人员希望我使用用户名而不是公开他们的电子邮件。问题是,并非所有用户都定义了用户名。我可以切换子路径,但每当遇到没有在注册时输入用户名的用户时,应用程序就会崩溃。虽然我稍后想要更改它,但这似乎是一个很好的练习:如果请求的值为零,我如何获得辅助值?

func getUsername(forUID uid: String, handler: @escaping (_ username: String) -> ()) {
        REF_USERS.observeSingleEvent(of: .value) { (userSnapshot) in
            guard let userSnapshot = userSnapshot.children.allObjects as? [DataSnapshot] else { return }
            for user in userSnapshot {
                if user.key == uid {
                    handler(user.childSnapshot(forPath: "username").value as! String)
                }
            }

1 个答案:

答案 0 :(得分:0)

这条线是造成崩溃的原因:

handler(user.childSnapshot(forPath: "username").value as! String)

原因是使用爆炸操作员!将你的力展开并将其作为字符串投射到此处:as! String。问题是如果没有任何内容并且返回nil值,则您无法将nil强制转换为String

例如。这是它在返回零值时所看到的:

handler(user.childSnapshot(forPath: "username").value as! String)
// since user.childSnapshot(forPath: "username").value == nil it sees
handler(nil as! String)

要理解的主要内容是,使用!强制展开某些内容,不管它是什么,它绝对不是nil。因此当它是时会出现崩溃。如果您不确定将返回什么,那么您应该使用?并使用可选绑定if letguard语句或零合并运算符??安全地解包解释如下

您必须在处理程序中使用Optional,以便它可以接受nil。

试试这个。

使它成为你的处理程序可以接受String类型的可选:

handler: @escaping (_ username: String?) // the question mark after the String makes it optional

然后,当调用处理程序时,如果用户名为nil,则使用nil合并运算符??提供默认值:

handler(user.childSnapshot(forPath: "username").value as? String ?? "defaultValue")

这是您的代码:

func getUsername(forUID uid: String, handler: @escaping (_ username: String?) -> ()) {
        REF_USERS.observeSingleEvent(of: .value) { (userSnapshot) in
            guard let userSnapshot = userSnapshot.children.allObjects as? [DataSnapshot] else { return }
            for user in userSnapshot {
                if user.key == uid {
                    handler(user.childSnapshot(forPath: "username").value as? String ?? "defaultValue")
                }
            }

以下是评论中您的问题的答案。在你的处理程序中,我将返回类型从()更改为String?所以它可以接受String类型的Optional。我把它改成了:

func getUsername(forUID uid: String, handler: @escaping (_ username: String?) -> () {

为:

func getUsername(forUID uid: String, handler: @escaping (_ username: String?) -> String? {

试试这个:

func getUsername(forUID uid: String, handler: @escaping (_ username: String?) -> String?) {
        REF_USERS.observeSingleEvent(of: .value) { (userSnapshot) in
            guard let userSnapshot = userSnapshot.children.allObjects as? [DataSnapshot] else { return }
            for user in userSnapshot {
                if user.key == uid {

                    // 1. you no longer use the nil coalescing operator because if you use it then you can't get a nil value
                    // 2. declare a local variable and name it value of Optional type String meaning it will accept nil or a String
                    var value: String? = handler(user.childSnapshot(forPath: "username").value as? String)
                    print("+++++value is: \(value ?? "value is nil")")                            

                    // 3. run a check on the value. If value is == nil then try your other node but you should probably use the nil coalescing operator there
                    // if value != nil which means username above returned a value other then nil then this won't run
                    if value == nil {
                       print("the username node was nil so use this different node")
                       value = handler(user.childSnapshot(forPath: "theDifferentNode").value as? String ?? "someDefaultValue") // if for some reason this is nil then this will have some default value
                       print("-----value is now: \(value)")
                    }
                }
            }