我对如何使用闭包有点困惑,或者在我的情况下有效地使用完成块。在我的情况下,我想在完成一些异步调用时调用一段代码,让我的调用者知道是否有错误或成功等等。
所以我想要完成的一个例子可能如下所示:
// Caller
updatePost(forUser: user) { (error, user) in
if let error = error {
print(error.description)
}
if let user = user {
print("User was successfully updated")
// Do something with the user...
}
}
public func updatePost(forUser user: User, completion: @escaping (Error?, User?) -> () {
// Not sure at what point, and where to call completion(error, user)
// so that my caller knows the user has finished updating
// Maybe this updates the user in the database
someAsyncCallA { (error)
}
// Maybe this deletes some old records in the database
someAsyncCallB { (error)
}
}
理想情况下,我希望在异步块B完成时调用完成块(假设异步块A已经完成,我知道这是一个BAD假设)。但是,在异步块B首先完成并且异步块A需要更长时间的情况下会发生什么?如果我在异步块B之后调用完成,那么我的调用者认为该方法已经完成。
在这样的情况下,假设我想在更新完成时告诉用户,但我只知道两个异步块完成时它已经完成。我如何解决这个问题,或者我只是使用了错误的闭包?
答案 0 :(得分:0)
我不知道您的问题是否已经回答。我认为您正在寻找的是DispatchGroup。
let dispatchGroup = DispatchGroup()
dispatchGroup.enter()
someAsyncCallA(completion: {
dispatchGroup.leave()
})
dispatchGroup.enter()
someAsyncCallB(completion: {
dispatchGroup.leave()
})
dispatchGroup.notify(queue: .main, execute: {
// When you get here, both calls are done and you can do what you want.
})
非常重要的注意事项:enter()
和leave()
呼叫必须保持平衡,否则您将因异常而崩溃。
答案 1 :(得分:-1)
尝试以下代码:
public func updatePost(forUser user: User, completion: @escaping (Error?, User?) -> () {
// Not sure at what point, and where to call completion(error, user)
// so that my caller knows the user has finished updating
// Maybe this updates the user in the database
someAsyncCallA { (error)
// Maybe this deletes some old records in the database
someAsyncCallB { (error)
completion()
}
}
}
请尝试以下更新的答案:
public func updatePost(forUser user: User, completion: @escaping (Error?, User?) -> () {
var isTaskAFinished = false
var isTaskBFinished = false
// Not sure at what point, and where to call completion(error, user)
// so that my caller knows the user has finished updating
// Maybe this updates the user in the database
someAsyncCallA { (error)
// Maybe this deletes some old records in the database
isTaskAFinished = true
if isTaskBFinished{
completion()
}
}
someAsyncCallB { (error)
isTaskBFinished = true
if isTaskAFinished{
completion()
}
}
}