I implemented PromiseKit
in Swift to avoid callback hell with completion blocks. I need to know the best way to chain promises together to init custom objects that have other associated objects. For example a Comment
object that has a User
object attached to it.
First I fetch the comments
from the DB, which all have a uid
property in the DB structure. I ultimately want to end up with an array of comments
, where each one has the correct user attached to it, so I can load both the comment
and user
data. This all seemed much easier with completion blocks, but I'm a total Promise
noob so idk.
Here is the code in the controller that handles fetch
CommentsService.shared.fetchComments(withPostKey: postKey)
.then { comments -> Promise<[User]> in
let uids = comments.map({ $0.uid })
return UserService.shared.fetchUsers(withUids: uids)
}.done({ users in
// how to init Comment object with users now?
})
.catch { error in
print("DEBUG: Failed with error \(error)")
}
Here is comment fetch function:
func fetchComments(withPostKey postKey: String) -> Promise<[Comment]> {
return Promise { resolver in
REF_COMMENTS.child(postKey).observeSingleEvent(of: .value) { snapshot in
guard let dictionary = snapshot.value as? [String: AnyObject] else { return }
let data = Array(dictionary.values)
do {
let comments = try FirebaseDecoder().decode([Comment].self, from: data)
resolver.fulfill(comments)
} catch let error {
resolver.reject(error)
}
}
}
}
Here is fetch users function
func fetchUsers(withUids uids: [String]) -> Promise<[User]> {
var users = [User]()
return Promise { resolver in
uids.forEach { uid in
self.fetchUser(withUid: uid).done { user in
users.append(user)
guard users.count == uids.count else { return }
resolver.fulfill(users)
}.catch { error in
resolver.reject(error)
}
}
}
}
Here is comment object:
struct Comment: Decodable {
let uid: String
let commentText: String
let creationDate: Date
var user: User?
}
This is how simple it is with completion blocks, starting to think Promises aren't worth it?
func fetchComments(withPostKey postKey: String, completion: @escaping([Comment]) -> Void) {
var comments = [Comment]()
REF_COMMENTS.child(postKey).observe(.childAdded) { (snapshot) in
guard let dictionary = snapshot.value as? [String: AnyObject] else { return }
guard let uid = dictionary["uid"] as? String else { return }
UserService.shared.fetchUser(withUid: uid, completion: { (user) in
let comment = Comment(user: user, dictionary: dictionary)
comments.append(comment)
completion(comments)
})
}
}