在 Swift 中链接 Promise 以初始化自定义对象
Posted
技术标签:
【中文标题】在 Swift 中链接 Promise 以初始化自定义对象【英文标题】:Chaining promises in Swift to initialize a custom object 【发布时间】:2019-11-05 18:18:02 【问题描述】:我在 Swift 中实现了PromiseKit
以避免带有完成块的回调地狱。我需要知道将 Promise 链接在一起以初始化具有其他关联对象的自定义对象的最佳方法。例如,Comment
对象附加了一个 User
对象。
首先我从数据库中获取comments
,它们在数据库结构中都有uid
属性。我最终希望得到一个comments
数组,每个数组都附加了正确的用户,所以我可以同时加载comment
和user
数据。使用完成块,这一切似乎都容易得多,但我是一个总 Promise
noob 所以 idk。
这是控制器中处理 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)")
这里是评论获取功能:
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?
完成块就是这么简单,开始认为 Promise 不值得?
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)
)
【问题讨论】:
我更喜欢 Rx 而不是 Promise 工具包,但在任何情况下,then
块在概念上就像一个 map
,如果你接受一个 Promise<T>
但返回一个 U
然后他输出是另一个Promise<U>
。 then
也可以像 flatMap 一样,如果你有一个 Promise<T>
但返回一个 Promise<U>
,那么输出是 Promise<U>
而不是 Promise <Promise<U>>
。在任何情况下,您都希望 a 从用户开始,因此返回 Promise<User>
或只是一个`用户`,然后您想要获取 cmets,因此从下一个 then block
返回 Promise<Comments>
或只是 Comments
我需要评论结构中的userIds
,以便知道要获取哪些用户,因此必须先获取 cmets
【参考方案1】:
好的,我想我明白你在做什么了。问题是您需要与用户一起捕获 cmets,以便您可以一起返回,然后再将它们组合起来。它应该看起来像这样:
CommentsService.shared.fetchComments(withPostKey: postKey)
.then comments -> Promise<[Comment], [User]> in
let uids = comments.map( $0.uid )
return UserService.shared.fetchUsers(withUids: uids)
.then users in
return Promise<[Comment], [User]>(comments, users)
.done( combined in
let (comments, users) = combined
//Do combiney stuff here
)
.catch error in
print("DEBUG: Failed with error \(error)")
转换是 [评论] -> [用户] -> ([评论], [用户]) -> [附有用户的评论]
【讨论】:
以上是关于在 Swift 中链接 Promise 以初始化自定义对象的主要内容,如果未能解决你的问题,请参考以下文章
《Promise学习笔记》- 4Promise自定义封装之thencatch的封装
Swift:不能以编程方式配置自定义表格单元格?没有调用初始化?
使用自定义初始化程序 swift 以编程方式实例化和推送视图控制器