从 viewDidAppear 呈现时,模态弹出框控制器不显示其内容

Modal popover controller does not show its content when presented from viewDidAppear

我有一个视图控制器,它在另一个视图控制器上显示为模态。如果它从 viewDidAppear 显示为 animated:NO,它不会在第二次显示时显示其内容。我已将问题缩小为:我添加了两个通过 segue 连接到故事板的控制器,每个控制器都在 viewDidAppear 中呈现相同的弹出框控制器。 它们中的每一个都是相同 class:

的一个实例
#import "ViewController.h"
#import "PopupViewController.h"

@interface ViewController () <UIPopoverPresentationControllerDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self showPopover];
}

-(UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller traitCollection:(UITraitCollection *)traitCollection {
    return UIModalPresentationNone;
}

- (void)showPopover {
    PopupViewController* popoverController = [[PopupViewController alloc] initWithNibName:NSStringFromClass([PopupViewController class]) bundle:nil];
    popoverController.modalPresentationStyle = UIModalPresentationPopover;
    popoverController.preferredContentSize = CGRectInset(self.view.bounds, 20, 100).size;
    popoverController.popoverPresentationController.sourceView = self.view;
    popoverController.popoverPresentationController.sourceRect = CGRectMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds), 0, 0);
    popoverController.popoverPresentationController.permittedArrowDirections = 0;
    popoverController.popoverPresentationController.delegate = self;
    [self presentViewController:popoverController animated:NO completion:nil];
}

@end

弹出窗口在应用程序启动时正确显示,但在按下第二个视图控制器和点击后退按钮时显示为空。如果我将 animated 更改为 YES,弹出窗口将正确显示。

编辑:如果我在 Xcode 中调试视图层次结构,视图会正确显示,所有框架都应该是:

这是它在设备上的样子(左边是正确的弹出窗口,右边是空的):

这个问题很容易重现。我开始记录事件,这似乎是由 UINavigationController 处理动画的方式引起的。

当为被推控制器调用viewDidAppear时,动画还没有结束。您可以通过检查 UINavigationControllerDelegate.

中的 navigationController:didShowViewController 方法亲眼看到

事件日志如下所示:

Navigation controller will show VC 1
VC 1 did layout subviews
VC 1 did layout subviews
VC 0 did move to parent <UINavigationController: 0x7feaf181ec00>
VC 1 did appear
VC 1 did move to parent <UINavigationController: 0x7feaf181ec00>
Navigation controller did show VC 1

请注意,在 viewDidAppear: 中,第二个控制器甚至没有完全移动到父级。

我发现的唯一可行的解​​决方法是:

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    dispatch_async(dispatch_get_main_queue(), ^{
        [self showPopover];
    });
}

这将使导航控制器完成其内部工作。

请注意,在没有动画的情况下推送时不会出现此问题,所以这可能是由于我们试图显示一个没有来自另一个动画完成块的动画的视图控制器,这意味着视图控制器层次结构事件的顺序是破碎的。添加 dispatch_async 将代码从完成块中移走,一切开始正常工作。