我有2个方法是我调用的,我需要产生一个包含这两个方法结果的模型,然后调用另一个方法。我需要生成一个包含这两个方法结果的模型,并调用另一个方法。
我想避免将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?
})
}
你可以将这两个异步调用结果存储为可选的属性。当你的回调发生时,设置这些属性,然后检查这两个属性是否已经被设置。如果它们已经被设置,你就知道两个异步调用都已经返回。
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.
}
这种方法的好处是,你可以使用模式轻松地添加更多的异步调用。但是,如果你需要一次进行那么多的异步网络调用,我建议你考虑重写你的服务器端逻辑,这样你只需要一个网络调用就可以实现这个功能。
另一种方法(我相信这种方法更简洁一些)是使用一个 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()
.