我有两种调用方法。我需要生成一个包含两者的结果的模型,然后调用另一个方法。
我想避免将1个方法放在另一个方法中,因为这可能会扩展为3或4个额外的调用。
基本上,一旦我获得了setUserFollowedState
和loadFollowersForTopic
的结果,我想将两个值都发送到另一个函数。
来自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?
})
}
答案 0 :(得分: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 :(得分: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()
。