如何防止尝试在已经呈现的控制器上显示控制器时出现错误?

时间:2017-03-06 01:36:36

标签: uiviewcontroller uinavigationcontroller modalviewcontroller presentviewcontroller

有一段时间,我会收到如下错误:

Warning: Attempt to present <Controller3>  on <Controller1> which is already presenting <Controller2>

据我所知,下一个控制器需要出现在堆栈顶部的控制器(Controller2)上,而不是下面某处的控制器(Controller1)。

不是一次性修复这些错误,我们如何设计我们的应用程序以一劳永逸地防止这个问题?

1 个答案:

答案 0 :(得分:0)

此问题的一个干净解决方案是导航控制器。

如果你不能或不想使用它,你可以在普通的视图控制器上轻松模拟它:

extension UIViewController {
  var topViewController: UIViewController {
    return presentedViewController == nil ? self : presentedViewController!.topViewController
  }

  // If the topmost view controller is an instance of one of the given classes, it's popped.
  // Then, the given view controller, if any, if pushed.
  //
  // This function can be called on any of the view controllers in the stack.
  func pop(ifOneOf: [AnyClass], thenPush: UIViewController? = nil) {
    if topViewController.presentingViewController != nil && topViewController.isKindOfOneOf(ifOneOf) {
      topViewController.dismiss(animated: false, completion: {
        self.pop(ifOneOf: [], thenPush: thenPush)
      })
      return
    }
    if thenPush != nil {
      push(thenPush!)
    }
  }

  // Pushes the given view controller onto the stack.
  //
  // This method can be called on any of the view controllers in the stack.
  func push(_ child: UIViewController) {
    topViewController.present(child, animated: true)
  }
}

extension NSObjectProtocol {
  func isKindOfOneOf(_ classes: [AnyClass]) -> Bool {
    for clazz in classes {
      if isKind(of: clazz) {
        return true
      }
    }
    return false
  }
}

如您所见,这提供了push()和pop(),类似于导航控制器。此外,您可以在堆栈中的任何控制器上调用这些方法,它会自动将它们重定向到最顶层的控制器,从而防止问题中的错误。

此扩展程序还解决了以下问题:如果要关闭控制器并显示另一个控制器,则只需在完成块中显示,即使您在没有动画的情况下解雇也是如此。否则,您将收到与上述相同的错误。此扩展程序修复了所有这些问题。