带有呈现的 UIAlertController 的 UINavigationController 被另外解雇

Posted

技术标签:

【中文标题】带有呈现的 UIAlertController 的 UINavigationController 被另外解雇【英文标题】:UINavigationController with presented UIAlertController gets additionally dismissed 【发布时间】:2017-10-12 13:02:07 【问题描述】:

我有这个UIAlertController,我以模态方式呈现在最顶层的视图控制器之上,如下所示:

UIViewController *top = [Utility topController];

UIAlertController *alertController
= [UIAlertController alertControllerWithTitle:@"Error"
                                      message:@"input string too long"
                               preferredStyle:UIAlertControllerStyleAlert];

UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) 
  ];

[alertController addAction:ok];

UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) 
  ];

[alertController addAction:cancel];

[top presentViewController:alertController
                  animated:true
                completion:nil];

我找到最顶层视图控制器的方法是循环显示呈现的视图控制器并确保我没有出现在警报控制器之上:

+ (UIViewController *)topController 
  UIViewController *topController = [[[[UIApplication sharedApplication] delegate] window] rootViewController];

  while (topController.presentedViewController) 
    if ([topController.presentedViewController class] == [UIAlertController class]) 
      [topController.presentedViewController dismissViewControllerAnimated:YES completion:nil];
      break;
    
    topController = topController.presentedViewController;
  
  return topController;

这一切都很好,无论顶部控制器是什么 UIViewController 都呈现UIAlertController,因为它是presentedViewController。当我点击确定或取消时,UIAlertController 被隐式​​关闭。但是,我有一个自定义的UINavigationController,它被呈现在上面,并且由于某种原因,UINavigationController 也有它被覆盖的dismissViewControllerAnimated: 被调用。

- (void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion 
    [super dismissViewControllerAnimated:flag completion:completion];

为什么UINavigationControllerpresentedViewController 和它自己一样被驳回?我应该补充一点,我像这样呈现UINavigationController

[self presentViewController:nav animated:YES completion:nil];

为什么dismissViewControllerAnimated: 似乎被调用了两次?对dismissViewControllerAnimated 的隐式调用不应该只在UINavigationControllerpresentedViewControllerUIAlertController 上调用吗?

【问题讨论】:

【参考方案1】:

您在“***”代码中调用了dismissViewController,这对我来说根本没有任何意义。

任何呈现的 UIAlertController 都应该在显示警报后返回,因此在任何给定时间点都应该只有一个 UIAlertController 处于活动状态,因此在尝试找到最顶层的 viewController 以显示新的 UIAlertController 时无需关闭之前的 UIAlertController .您不想随意关闭用户的警报;你的应用需要告诉用户一些事情,所以让他们决定什么时候读完。

建议更改:

使用类别来查找当前的 viewController

@implementation UIViewController (Current)

#import "UIViewController+Current.h"

@implementation UIViewController (Current)

+(UIViewController*) findBestViewController:(UIViewController*)vc 

    if (vc.presentedViewController) 

        // Return presented view controller
        return [UIViewController findBestViewController:vc.presentedViewController];

     else if ([vc isKindOfClass:[UISplitViewController class]]) 

        // Return right hand side
        UISplitViewController* svc = (UISplitViewController*) vc;
        if (svc.viewControllers.count > 0)
            return [UIViewController findBestViewController:svc.viewControllers.lastObject];
        else
            return vc;

     else if ([vc isKindOfClass:[UINavigationController class]]) 

        // Return top view
        UINavigationController* svc = (UINavigationController*) vc;
        if (svc.viewControllers.count > 0)
            return [UIViewController findBestViewController:svc.topViewController];
        else
            return vc;

     else if ([vc isKindOfClass:[UITabBarController class]]) 

        // Return visible view
        UITabBarController* svc = (UITabBarController*) vc;
        if (svc.viewControllers.count > 0)
            return [UIViewController findBestViewController:svc.selectedViewController];
        else
            return vc;

     else 

        // Unknown view controller type, return last child view controller
        return vc;

    


+(UIViewController*) currentViewController 
    // Find best view controller
    UIViewController* viewController = [UIApplication sharedApplication].keyWindow.rootViewController;
    return [UIViewController findBestViewController:viewController];

.h 文件

#import <UIKit/UIKit.h>

@interface UIViewController (Current)

+(UIViewController*) currentViewController;

@end

然后更改您的“顶”行以使用它

UIViewController *top = [UIViewController currentViewController];

【讨论】:

以上是关于带有呈现的 UIAlertController 的 UINavigationController 被另外解雇的主要内容,如果未能解决你的问题,请参考以下文章

呈现的 UIViewController 不能呈现 UIAlertController

从 AppDelegate 到 PresentedViewController 的警报:“尝试在...上呈现 UIAlertController 已经在呈现 UIAlertController”

在呈现的视图控制器上的 UITableViewCell 中呈现 UIAlertController

如何从 SKScene 呈现 UIAlertController

检查UIAlertController是否已经呈现的最佳方法是什么?

呈现 UIAlertController 时出现 CGContext 错误