在我的应用程序中,我有一个用于返回电子邮件的功能,但当然我的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)
}
}
答案 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 let
,guard
语句或零合并运算符??
安全地解包解释如下
您必须在处理程序中使用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)")
}
}
}