如何将这2个异步方法的结果结合起来?

问题描述 投票:0回答:1

我有2个方法是我调用的,我需要产生一个包含这两个方法结果的模型,然后调用另一个方法。我需要生成一个包含这两个方法结果的模型,并调用另一个方法。

我想避免将1个方法放在另一个方法里面,因为这可能会扩展出3或4个额外的调用。

基本上,一旦我有了以下方法的结果 setUserFollowedStateloadFollowersForTopic 我想把这两个值发送到另一个函数。

来自JS领域的我将使用 async/await 但这在Swift中并不存在。

  func setUserFollowedState() {
    following.load(for: userID, then: { [weak self, topic] result in
      guard self != nil else { return }
      let isFollowed = (try? result.get().contains(topic)) ?? false
      // do something with isFollowed?

    })
  }

  func loadFollowersForTopic() {
    followers.load(topic, then: { [weak self, topic] result in
      guard self != nil else { return }
      let count = (try? result.get().first(where: { $0.tag == topic })?.followers) ?? 0
      // do something with count?
    })
  }
swift asynchronous callback
1个回答
1
投票

你可以将这两个异步调用结果存储为可选的属性。当你的回调发生时,设置这些属性,然后检查这两个属性是否已经被设置。如果它们已经被设置,你就知道两个异步调用都已经返回。

private var isFollowed: Bool?
private var count: Int?

func setUserFollowedState() {
    following.load(for: userID, then: { [weak self, topic] result in
        guard let self = self else { return }
        let isFollowed = (try? result.get().contains(topic)) ?? false

        self.isFollowed = isFollowed
        performPostAsyncCallFunctionality()
    })
}

func loadFollowersForTopic() {
    followers.load(topic, then: { [weak self, topic] result in
        guard let self = self else { return }
        let count = (try? result.get().first(where: { $0.tag == topic })?.followers) ?? 0

        self.count = count
        performPostAsyncCallFunctionality()
    })
}

private func performPostAsyncCallFunctionality() {
    // Check that both values have been set.
    guard let isFollowed = isFollowed, let count = count else { return }

    // Both calls have returned, do what you need to do.
}

这种方法的好处是,你可以使用模式轻松地添加更多的异步调用。但是,如果你需要一次进行那么多的异步网络调用,我建议你考虑重写你的服务器端逻辑,这样你只需要一个网络调用就可以实现这个功能。


1
投票

另一种方法(我相信这种方法更简洁一些)是使用一个 DispatchGroup 来组合上述方法的结果。

你可以修改你原来的方法,取一个完成处理程序,然后在你真正需要数据的地方把两个结果结合起来。

func setUserFollowedState(completion: @escaping ((Bool) -> Void)) {
  following.load(for: userID, then: { [weak self, topic] result in
    guard self != nil else { return }
    let isFollowed = (try? result.get().contains(topic)) ?? false
    // Call completion with isFollowed flag
    completion(isFollowed)
  })
}

func loadFollowersForTopic(completion: @escaping ((Int) -> Void)) {
  followers.load(topic, then: { [weak self, topic] result in
    guard self != nil else { return }
    let count = (try? result.get().first(where: { $0.tag == topic })?.followers) ?? 0
    // Call completion with follower count
    completion(count)
  })
}

func loadFollowedAndCount() {
    let group = DispatchGroup()

    var isFollowed: Bool?
    // Enter group before triggering data fetch
    group.enter()
    setUserFollowedState { followed in
        // Store the fetched followed flag
        isFollowed = followed
        // Leave group only after storing the data
        group.leave()
    }

    var followCount: Int?
    // Enter group before triggering data fetch
    group.enter()
    loadFollowersForTopic { count in
        // Store the fetched follow count
        followCount = count
        // Leave group only after storing the data
        group.leave()
    }

    // Wait for both methods to finish - enter/leave state comes back to 0
    group.notify(queue: .main) {
        // This is just a matter of preference - using optionals so we can avoid using default values
        if let isFollowed = isFollowed, let followCount = followCount {
            // Combined results of both methods
            print("Is followed: \(isFollowed) by: \(followCount).")
        }
    }
}

编辑:始终确保一个 group.enter() 随后是 group.leave().

© www.soinside.com 2019 - 2024. All rights reserved.