假设我有一个 ViewController A 和一个类 B。
当我按下 A 中的某个按钮时,它调用一个 IBAction,该 IBAction 调用一个函数 B.foo(),该函数返回一个 Int
B.foo() 需要 8~10 秒才能完成,当它运行时我想在 A 上放一个 Loading...
动画,当 B.foo() 完成时,动画将停止。
我该怎么做?这是我想要的伪代码示例:
@IBAction func buttonPressed(_ sender: UIButton){
UIView.animate(blablabla......)
DO({
self.answer = B.foo()
}, andWhenItFinishesDo: {
self.someone.layer.removeAllAnimation()
})
}
最佳答案
这是一个很常见的问题。解决它的一种方法是使用不同的队列(您可以将它们视为可以并行发生的工作线)。
基本思想是,一旦按下按钮,就会显示加载指示器并将长时间的工作“分派(dispatch)”到辅助队列,辅助队列将在后台运行并完成工作。这可确保您的主队列在工作进行时不会阻塞,并且用户界面保持响应。
现在的诀窍是您希望在长时间的工作完成时收到通知,以便您可以停止显示加载指示器(并可能做更多)。
虽然您实际上可以使用某种通知系统,但还有其他一些有时更合适的方法。如果您可以告诉长时间运行的函数使用您提供的代码专门给您回电,实际上会更方便。
这就是“完成处理程序”或“回调”的基本概念。
整个事情看起来像这样:
// Some made up class here
class B {
// This is only static because I do not have an instance of B around.
static func foo(completion: @escaping (Int) -> Void ) {
// The method now does all of its work on a background queue and returns immediately
DispatchQueue.global(qos: .background).async {
// In the background this may take as long as it wants
let result = longCalculation()
// VERY important. The caller of this function might have a certain
// expectation about on which queue the completion handler runs.
// Here I just use the main queue because this is relatively safe.
// You could let the caller provide a queue in the function
// parameters and use it here
DispatchQueue.main.async {
// The completion handler is a function that takes an Int.
// That is exactly what you are providing here
completion(result)
}
}
}
}
@IBAction func buttonPressed(_ sender: UIButton){
self.showLoadingIndicator()
// The foo function now takes a completion handler that gets the result in.
// You have to provide this function here and do something with the result
//
// The completion handler will only be run when the foo function calls it
// (which is after the computation as you can see in the method above.
//
// I am also telling the completion handler here that self should not be
// held on to as the view controller might already have gone away when the
// long calculation finished. The `[weak self]` thingy makes that inside
// your completion handler self is an optional and might be nil (and it
// doesn't hold a strong reference to self, but that's a whole other topic)
B.foo(completion: { [weak self] result in
// Do something with the result
// Since we are called back on the main queue we can also do UI stuff safely
self?.hideLoadingIndicator()
})
}
希望对您有所帮助。
异步编程可能很难学,但您可以找到大量关于该主题的教程和示例。
关于ios - Swift:功能结束时的反馈,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43817401/