I had this code before using completion and it worked and still works perfectly:
func fetchUser(withUid uid: String, completion: @escaping(UserModel) -> Void) {
Firestore.firestore().collection("users")
.document(uid)
.getDocument { snapshot, _ in
guard let snapshot = snapshot else {return}
guard let user = try? snapshot.data(as: UserModel.self) else {return}
completion(user)
}
}
but when i switched to async / await i get this error:
Cannot get keyed decoding container -- found null value instead.
With this code:
func fetchUser(withUid uid: String) async throws -> UserModel {
do {
let snapshot = try await Firestore.firestore().collection("users").document(uid).getDocument()
do {
let user = try snapshot.data(as: UserModel.self)
return user
} catch {
throw(error)
}
} catch {
throw(error)
}
}
Any tips on where i went wrong?
Switched to async code and got an error with decoding
We are comparing apples to oranges here, because your completion handler rendition is not reporting errors, but rather just doing an immediate
returnwithout calling the completion handler. So you might be failing in the completion handler pattern without ever knowing, which is what I suspect is happening here.Here is the standard completion handler pattern with a
Resulttype that handles both.successand.failure:With completion handlers, you want to make sure every path of execution calls the completion handler closure. (As an aside, that nil-coalescing operator,
??, with.notFoundprobably is not needed, because I believe that ifsnapshotisnil, there must be anerror, but I always try to be defensive in my error handling code.)Anyway, you would then have a
switchstatement on the result:For more information, see Writing Failable Asynchronous APIs.
The
asyncrendition could be simplified to:As you can see, there is no need for any
do-catchblocks in the above, if all you plan on doing is rethrowing the error. Thetrywill automatically throw the error for you.Anyway, you can then call it with: