【问题标题】:What Completion Handlers Should I Write?我应该写什么完成处理程序?
【发布时间】:2018-05-25 13:56:15
【问题描述】:

刚刚了解了如何创建完成处理程序,我在原则上理解它们,但我不知道如何将这些想法付诸实践以完成我所需要的。

我有以下通用代码和故事板结构:sessionVC(一个 UIViewController)及其 UIView 拥有一个容器视图,其中包含一个嵌入到 animationVC(也是 UIViewController)及其 SKView 的 segue。

从 sessionVC 我想在 animationVC 的 SKView 中运行一系列动画。我希望尽快准备好每个动画(例如,在每个之前的动画仍在运行时),并且我希望每个动画在开始之前等待最后一个动画完成。请参阅下面的代码。

我的问题是,我应该在我的代码中放置什么来代替 ???s 来完成我想要的效果(上面提到,以及在代码 cmets 中的每个 *** 之后)?

// TO DELEGATE ANIMATION TO animationVC
protocol AnimateContentDelegate: AnyObject {

    prepareContent(_ Content, contentWasPrepared: ???)
    animateContent(animationDidComplete: ???)
    playAnimation()
    pauseAnimation()
}

// CONTROL THE OVERALL SESSION
class sessionVC: UIViewController {

    // INITIALIZE contentArray

    weak var delegate: AnimateContentDelegate?

    override func viewDidLoad {
        super.viewDidLoad()

        delegate = self.childViewControllers[0] as? AnimateContentDelegate

        runSession(contentArray)
    }

    func runSession(_ contentArray) {

        for content in contentArray {

            delegate?.prepareContent(content, contentWasPrepared: ???)

            // ***DON’T START THE NEXT ANIMATION UNTIL contentWasPrepared
            //    DO CONTINUE THE CURRENT ANIMATION, AND ALLOW INTERACTIONS

            delegate?.animateContent(animationDidComplete: ???)

            // ***DON’T START THE NEXT ANIMATION UNTIL animationDidComplete
            //    DO CONTINUE THE CURRENT ANIMATION, AND ALLOW INTERACTIONS
       }
    }

    @IBAction func playOrPause(_ sender: UILongPressGestureRecognizer) {

         if sender == .possible || sender.state == .ended {

            delegate?.playAnimation()

        } else if sender.state == .began {

            delegate?.pauseAnimation()
        }
    }
}

// PREPARE AND ANIMATE CURRENT CONTENT
class animationVC: UIViewController, AnimateContentDelegate {

    // SET UP SKVIEW

    func prepareContent(_ content: Content, prepCompleteHandler: ???) {
       // PREPARE THE CONTENT
       // ***REPORT WHEN IT IS FINISHED
    }

    func animateContent(animationCompleteHandler: ???) {
        // ANIMATE THE CONTENT
        // ***REPORT IF IT RAN TO COMPLETION
   }

    func playAnimation() {
        skView?.scene?.isPaused = false
    }

    func pauseAnimation() {
        skView?.scene?.isPaused = true
    }
}

【问题讨论】:

    标签: ios swift completionhandler


    【解决方案1】:

    按照通常的约定,您可以用稍微不同的措辞声明函数:

    prepareContent(_ Content, completionHandler: { () -> Void })
    animateContent(completionHandler: { () -> Void })
    

    然后,在 SET UP SKVIEW 下方,您可以像这样调用委托函数:

    delegate?.prepareContent(content, completionHandler: {
        self.delegate.animateContent(completionHandler: {
            // do whatever needs to be done upon completion
        })
    })
    

    (您也可以使用尾随闭包语法。) 通过像这样嵌套委托调用,您可以确保动画仅在准备完成后执行。

    函数体如下所示:

    func prepareContent(_ content: Content, completionHandler: (() -> Void)) {
        // ...
        completionHandler()
    }
    
    func animateContent(completionHandler: (() -> Void)) {
        // ...
        completionHandler()
    }
    

    如果您更喜欢使用可选的完成处理程序,i。 e.那些可以为零的,改变这样的功能:

    func prepareContent(_ content: Content, completionHandler: (() -> Void)?) {
        // ...
        completionHandler?()
    }
    

    【讨论】:

    • 感谢@Tom E 的指导。将 animateContent 函数嵌套在一个块中作为 prepareContent 的完成处理程序是最大的帮助,但是您对我的代码的其他修复使一切变得容易理解。
    • @Optimalist:很高兴我能帮上忙!
    【解决方案2】:

    它应该看起来像:

    func prepareContent(_ content: Content, completionHandler: @escaping (Bool, Any?) -> Void) -> Void {
    
       var finished : Bool = false
       var output : Any? = nil
    
       // prepare the content
       // possibly update the output
    
       //when ready : 
       finished = true
       completionHandler(finished, output)
    
    }
    

    那你就用它吧:

    prepareContent(content: content, completionHandler: { (f, o) in 
       if f {
          if o != nil {
              //do something
          }
          //else handle error
       }
       //else handle error
    })
    

    您可以根据需要调整它,根据需要添加更多或更少的输出、错误日志等。

    【讨论】:

    • 动画方法或使用完成处理程序的任何方法也是如此
    【解决方案3】:

    你想要这样的东西吗?

    protocol AnimateContentDelegate: AnyObject {
        func prepareContent(content : Content, contentWasPrepared: ((Bool) -> Void)?)
        func animateContent(animationDidComplete: ((Bool) -> Void)?)
        func playAnimation()
        func pauseAnimation()
    }
    
    class YourObject : AnimateContentDelegate {
    
    func prepareContent(content: Content, contentWasPrepared: ((Bool) -> Void)?) {
        // prepare content
    }
    
    func animateContent(animationDidComplete: ((Bool) -> Void)?) {
        // animate content
    }
    
    func playAnimation() {
    
    }
    
    func pauseAnimation() {
    
    }
    

    }

    这样使用:

    let yourObject = YourObject()
    yourObject.animateContent(animationDidComplete: { finished in
        // animation did complete
    })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-24
      • 1970-01-01
      • 2019-11-01
      相关资源
      最近更新 更多