如何防止尝试在已经呈现的控制器上呈现控制器时出现错误?
How do I prevent errors about trying to present a controller on a controller which is already presenting?
偶尔,我会收到如下错误:
Warning: Attempt to present <Controller3> on <Controller1> which is already presenting <Controller2>
我知道下一个控制器需要出现在堆栈顶部的控制器 (Controller2) 上,而不是下面某处的控制器 (Controller1)。
与其一次性修复此类错误,不如我们如何设计我们的应用程序来一劳永逸地防止此问题?
这个问题的一个干净的解决方案是导航控制器。
如果你不能或不想使用一个,你可以很容易地在一个普通的视图控制器上模拟它:
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(),类似于导航控制器。此外,您可以在堆栈中的任何控制器上调用这些方法,它会自动将它们重定向到最顶层控制器,从而避免问题中的错误。
此扩展程序还解决了以下问题:如果您想关闭一个控制器并显示另一个控制器,您只需在完成块中显示,即使您在没有动画的情况下关闭也是如此。否则,您将得到与上述相同的错误。此扩展程序修复了所有这些问题。
偶尔,我会收到如下错误:
Warning: Attempt to present <Controller3> on <Controller1> which is already presenting <Controller2>
我知道下一个控制器需要出现在堆栈顶部的控制器 (Controller2) 上,而不是下面某处的控制器 (Controller1)。
与其一次性修复此类错误,不如我们如何设计我们的应用程序来一劳永逸地防止此问题?
这个问题的一个干净的解决方案是导航控制器。
如果你不能或不想使用一个,你可以很容易地在一个普通的视图控制器上模拟它:
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(),类似于导航控制器。此外,您可以在堆栈中的任何控制器上调用这些方法,它会自动将它们重定向到最顶层控制器,从而避免问题中的错误。
此扩展程序还解决了以下问题:如果您想关闭一个控制器并显示另一个控制器,您只需在完成块中显示,即使您在没有动画的情况下关闭也是如此。否则,您将得到与上述相同的错误。此扩展程序修复了所有这些问题。