I am trying to adhere to MVC practices and keep all the network code inside the data service class that I am using in my app. On one screen I have the user\'s name and usern
You are confusing your grabUserData
function return value with the Firebase closure return value — the former is User
but the latter is Void
;)
You are actually returning from this closure — I'm now using a explicit return type to be clear:
{
(snapshot) -> Void in
if let userDict = snapshot.value as? Dictionary<String,String> {
let user = User(
first: userDict["firstName"]!,
last: userDict["lastName"]!,
username: userDict["username"]!
)
return user
}
}
which is passed as the last argument to the observeSingleEvent
Firebase function. This is a very common mistake ;)
Completion handler. A standard pattern here is to return the desired User
via a completion handler instead. This solution nicely models the asynchronous nature of network requests such as Firebase database calls. For instance:
func grabUserData(completion: @escaping (User?) -> Void) {
REF_USERS.child(getCurrentUID()).observeSingleEvent(of: .value) {
(snapshot) in
if let userDict = snapshot.value as? Dictionary<String, String> {
let user = User(
first: userDict["firstName"]!,
last: userDict["lastName"]!,
username: userDict["username"]!
)
completion(user) // Returns user!
} else {
completion(nil) // User not found!
}
}
}
Finally, in your data service client code, call it like this:
grabUserData() {
(user) in
if let user = user {
print("Grabbed user: \(user)")
} else {
print("User not found!")
}
}