Эта строка вызывает ошибку:
handler(user.childSnapshot(forPath: "username").value as! String)
Причина в том, что с помощью оператора взрыва !
ваша сила развернула его и применила в качестве строки здесь: as! String
. Проблема в том, что если там ничего нет и возвращается значение nil
, вы не можете разыграть nil
как String
.
например. это то, что он видит, когда возвращается значение nil:
handler(user.childSnapshot(forPath: "username").value as! String)
// since user.childSnapshot(forPath: "username").value == nil it sees
handler(nil as! String)
Главное, что нужно понять, это то, что путем принудительного распаковывания чего-либо, используя !
ваше изречение, что, что бы это ни было, это определенно не nil
. Таким образом, когда он равен nil , тогда произойдет крах . Если вы не уверены в том, что вернется, вам следует использовать ?
и безопасно развернуть его с помощью необязательного связывания if let
, оператора guard
или оператора объединения нулей ??
, как описано ниже
Вы должны использовать Optional
внутри вашего обработчика, чтобы он мог принимать ноль.
Попробуйте это.
Сделайте так, чтобы ваш обработчик мог принять Optional типа 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. Я изменил это с:
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)")
}
}
}