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

Posted

技术标签:

【中文标题】如何防止尝试在已经呈现的控制器上呈现控制器时出错?【英文标题】:How do I prevent errors about trying to present a controller on a controller which is already presenting? 【发布时间】:2017-03-06 01:36:35 【问题描述】:

偶尔会遇到如下错误:

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

我了解下一个控制器需要显示在堆栈顶部的控制器 (Controller2) 上,而不是下方某处的控制器 (Controller1)。

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

【问题讨论】:

【参考方案1】:

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

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

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(),类似于导航控制器。此外,您可以在堆栈中的任何控制器上调用这些方法,它会自动将它们重定向到最顶层的控制器,从而防止问题中的错误。

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

【讨论】:

以上是关于如何防止尝试在已经呈现的控制器上呈现控制器时出错?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用已经呈现的模式视图控制器启动 iOS 应用程序,而用户无法看到呈现视图?

如何在模态呈现的视图控制器上执行呈现模态序列?

在已经呈现的表单上呈现模态视图

在 UINavigationBar 上呈现 UISearchController 时推送视图控制器

如何使用 animateWithDuration:在 iOS 7 上呈现视图控制器时?

如何在按钮单击时将部分视图呈现为模式弹出窗口?