容器视图控制器不转发外观方法

Posted

技术标签:

【中文标题】容器视图控制器不转发外观方法【英文标题】:Container View Controller not forwarding appearance methods 【发布时间】:2013-01-31 17:17:40 【问题描述】:

我正在尝试创建一个容器视图控制器以在屏幕上同时保存 UINavigationController 和自定义 UIViewController。

我在一个测试程序中对其进行了布局,它运行良好,但是当我尝试在我的实际项目中实现它时,包含视图控制器的外观方法永远不会被调用。

工作测试:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 

self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

MasterStatusViewController *master = [[MasterStatusViewController alloc] init];
[self.window setRootViewController:master];

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;


- (void)viewDidLoad 

[super viewDidLoad];

InventoryViewController *newInventory = [[InventoryViewController alloc] init];
self.navigation = [[UINavigationController alloc] initWithRootViewController:newInventory];
self.statusRibbon = [[StatusBarViewController alloc] initWithNibName:@"StatusBarViewController" bundle:nil];

[self addChildViewController:self.navigation];
self.navigation.view.frame = self.navigationView.frame;
[self.view addSubview:self.navigation.view];
[self.navigation didMoveToParentViewController:self];

[self addChildViewController:self.statusRibbon];
self.statusRibbon.view.frame = self.ribbonView.frame;
[self.view addSubview:self.statusRibbon.view];
[self.statusRibbon didMoveToParentViewController:self];

失败的项目:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 

self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];

MasterViewController *master = [[MasterViewController alloc] init];
self.centerController = master;

[self.window setRootViewController:master];

[self.window makeKeyAndVisible];
return YES;


- (void)viewDidLoad 

[super viewDidLoad];

LoginViewController *login = [[LoginViewController alloc] init];
self.navigation = [[UINavigationController alloc] initWithRootViewController:login];
self.statusRibbon = [[StatusRibbonViewController alloc] init];

[self addChildViewController:self.navigation];
self.navigation.view.frame = self.navigationView.frame;
[self.view addSubview:self.navigation.view];
[self.navigation didMoveToParentViewController:self];

[self addChildViewController:self.statusRibbon];
self.statusRibbon.view.frame = self.ribbonView.frame;
[self.view addSubview:self.statusRibbon.view];
[self.statusRibbon didMoveToParentViewController:self];

视图排列正确并按预期执行,除了外观方法永远不会被调用。我很困惑。手动调用方法似乎不是解决方案,因为这些调用也没有通过。

编辑:外观方法是指 viewWillAppear、viewDidAppear 等。

第二次编辑:

~剪断~

第三次编辑:经过进一步检查,我认为没有调用外观生命周期方法的原因是因为它们也没有在容器视图控制器上被调用。我加了

- (void)viewWillAppear:(BOOL)animated 
    [super viewWillAppear:animated];
    NSLog(@"MasterViewController VIEW WILL APPEAR");


- (void)viewDidAppear:(BOOL)animated 
    [super viewDidAppear:animated];
    NSLog(@"MasterViewController VIEW DID APPEAR");

masterViewController 什么都没有,由于某种原因,它们永远不会被调用。

【问题讨论】:

【参考方案1】:

解决了。我不知道为什么没有调用主外观方法,一些 xcode 的清理似乎解决了这个问题。

但是,这些方法仍然没有被转发到我的其他视图控制器。然后我遇到了this link 并了解到无论如何你都必须将外观呼叫转发给他们。我可以通过添加来修复它:

- (void)viewWillAppear:(BOOL)animated 

    [super viewWillAppear:animated];
    [self.navigation beginAppearanceTransition: YES animated: animated];


- (void)viewDidAppear:(BOOL)animated 

    [super viewDidAppear:animated];
    [self.navigation endAppearanceTransition];


-(void) viewWillDisappear:(BOOL)animated 

    [super viewWillDisappear:animated];
    [self.navigation beginAppearanceTransition: NO animated: animated];


-(void) viewDidDisappear:(BOOL)animated 

    [super viewDidDisappear:animated];
    [self.navigation endAppearanceTransition];


- (void)didReceiveMemoryWarning 

    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.

【讨论】:

【参考方案2】:

我在使用 UIViewController 的包含功能时遇到了类似的问题,每当我向视图添加新的子视图控制器时,外观方法都不会被转发。

事实证明,您需要在添加子视图和 endApperanceTransition 之前调用 beginAppearanceTransition:animated: 完成后。当您添加子视图以及删除它以触发外观方法时,您将需要执行此操作。

对于你的情况,我会尝试这样的事情:

self.navigation.view.frame = self.navigationView.frame;
[self addChildViewController:self.navigation];
[self.navigation didMoveToParentViewController:self]
[self.navigation beginAppearanceTransition:YES animated:NO];
[self.view addSubview:self.navigation.view];
[self.navigation endAppearanceTransition];

self.statusRibbon.view.frame = self.ribbonView.frame;
[self addChildViewController:self.statusRibbon];
[self.statusRibbon didMoveToParentViewController:self]
[self.statusRibbon beginAppearanceTransition:YES animated:NO];
[self.view addSubview:self.statusRibbon.view];
[self.statusRibbon endAppearanceTransition];

【讨论】:

【参考方案3】:

你所说的“外观方法”到底是什么意思?你的意思是,视图没有出现?

在您的工作示例中,您正在从 nib 文件加载功能区视图:

self.statusRibbon = [[StatusBarViewController alloc] initWithNibName:@"StatusBarViewController" bundle:nil];

而你在第二个代码示例中只是 init 它:

self.statusRibbon = [[StatusRibbonViewController alloc] init];

后者只是创建一个“新鲜”视图,这可能会导致您认为它不会出现。

【讨论】:

它实际上看起来很好,但是viewWillAppear,viewDidAppear,所有这些都不会在子视图中被调用。 那么,您是说viewWillAppear 等在LoginViewControllerStatusRibbonViewController 的实现中永远不会被调用?那我们就得看看这些类的代码了。 已添加,尽管您可以看到 StatusRibbon 实际上还没有做任何事情,但在演示项目中,所有内容都被调用,在生产项目中,没有 viewWillAppear 或 viewDidAppear。我也尝试过消失方法,它们也没有被调用。 由于您没有覆盖init 方法并在其中调用initWithNibName,因此您的视图不会加载,因此不会显示。视图控制器的指定初始化方法是 initWithNibName - 而不是 init。正如我在回答中所写:您对self.statusRibbon 的初始化是问题所在。 我很欣赏这个建议,但我认为这不是问题所在。我尝试在非工作版本中覆盖-(id)init,但它仍然不起作用然后我将statusRibbon更改为initWithNibNamed,但它没有帮助。我还将工作版本中的初始化程序从 initWithNibNamed 更改为 init 并且它继续像以前一样工作。它肯定正在显示,如果我运行程序,我可以看到它。如果我尝试导航到新屏幕,我会收到Unbalanced calls to begin/end appearance transitions,这并不奇怪。

以上是关于容器视图控制器不转发外观方法的主要内容,如果未能解决你的问题,请参考以下文章

无法在没有动画的情况下呈现和关闭视图控制器并获得不平衡调用以开始/结束外观转换

父视图中容器视图的自动布局未与布局指南对齐

设置 UINavigationBar 外观 whenContainedInInstancesOf 到我的视图控制器不起作用

在视图控制器中重置导航栏的外观

为视图控制器根视图设置外观代理

touchesBegan 不调用容器视图控制器