Я реализовал PromiseKit
в Swift, чтобы избежать ада обратного вызова с блоками завершения. Мне нужно знать, как лучше всего объединить обещания для инициализации пользовательских объектов, имеющих другие связанные объекты. Например, объект Comment
, к которому прикреплен объект User
.
Сначала я выбираю comments
из БД, у всех которых есть свойство uid
в структуре БД. В конечном итоге я хочу получить массив comments
, где к каждому из них прикреплен правильный пользователь, поэтому я могу загрузить данные comment
и user
. Все это выглядело намного проще с блоками завершения, но я в целом Promise
noob, так что idk.
Вот код в контроллере, который обрабатывает выборку
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)")
}
Вот функция выборки комментария:
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)
}
}
}
}
Вот функция выборки пользователей
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)
}
}
}
}
Вот объект комментария:
struct Comment: Decodable {
let uid: String
let commentText: String
let creationDate: Date
var user: User?
}
Насколько просто с блоками завершения начать думать, что Обещания не стоят того?
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)
})
}
}