【问题标题】:Chaining promises in Swift to initialize a custom object在 Swift 中链接 Promise 以初始化自定义对象
【发布时间】:2019-11-05 18:18:02
【问题描述】:

我在 Swift 中实现了PromiseKit 以避免带有完成块的回调地狱。我需要知道将 Promise 链接在一起以初始化具有其他关联对象的自定义对象的最佳方法。例如,Comment 对象附加了一个 User 对象。

首先我从数据库中获取comments,它们在数据库结构中都有uid 属性。我最终希望得到一个comments 数组,每个数组都附加了正确的用户,所以我可以同时加载commentuser 数据。使用完成块,这一切似乎都容易得多,但我是一个总 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&lt;T&gt; 但返回一个 U 然后他输出是另一个Promise&lt;U&gt;then 也可以像 flatMap 一样,如果你有一个 Promise&lt;T&gt; 但返回一个 Promise&lt;U&gt;,那么输出是 Promise&lt;U&gt; 而不是 Promise &lt;Promise&lt;U&gt;&gt;。在任何情况下,您都希望 a 从用户开始,因此返回 Promise&lt;User&gt; 或只是一个`用户`,然后您想要获取 cmets,因此从下一个 then block 返回 Promise&lt;Comments&gt; 或只是 Comments
  • 我需要评论结构中的userIds,以便知道要获取哪些用户,因此必须先获取 cmets

标签: swift promise promisekit


【解决方案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)")
}

转换是 [评论] -> [用户] -> ([评论], [用户]) -> [附有用户的评论]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多