ios - Swift:功能结束时的反馈

标签 ios swift

假设我有一个 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/

相关文章:

ios - 添加参数到URL(来自路径的资源,WKWebView)

ios - Amazon Device Farm 的 KIF .xctest 目录

ios - 保存为 GIF 后图像质量下降

Swift:Alamofire 文档

ios - 如何快速按下按钮以在Xcode上产生声音?

objective-c - NSFetchedRequestController,其中NSSet属性为sectionNameKeyPath。可能吗?

iOS 分发问题

ios - viewmodel和view如何通信?

ios - 使用 danielgindi/Charts 框架的 ios 中的烛台图表未正确显示

iOS swift : nil IBOutlets with custom ViewController