parentViewController 总是导航控制器吗?

Posted

技术标签:

【中文标题】parentViewController 总是导航控制器吗?【英文标题】:Is parentViewController always a Navigation controller? 【发布时间】:2008-10-28 19:48:25 【问题描述】:

一周前我对此有点摸不着头脑,现在有了更多可可经验,我觉得我对可能发生的事情有所了解。

我正在制作一个由 UINavigationController 驱动的应用程序。在 AppDelegate 中,我创建了这个类的一个实例,使用“page 1”作为根视图控制器。

UINavigationController *aNavigationController = [[UINavigationController alloc] 
     initWithRootViewController:page1ViewController];

现在这就是我遇到问题的地方。从“第 1 页”开始,我想使用一个模态视图控制器,它在界面上滑动,然后在用户进行编辑后消失。我在 Page1ViewController 内部使用这样的代码来做到这一点:

[self presentModalViewController:myModalViewController animated:YES];

当模态视图控制器消失时,我希望根据用户在模态视图控制器中输入的内容更改“第 1 页”上的值。所以,我写了一些这样的代码,它驻留在模态视图控制器中:

[self.parentViewController dismissModalViewControllerAnimated:YES];
[self.parentViewController doSomethingPleaseWithSomeData:someData];

没有更新到第 1 页,我花了很长时间才意识到“doSomethingPleaseWithSomeData”消息没有发送到 Page1ViewController,而是发送到导航控制器。

在使用导航控制器时是否总是会出现这种情况?我是否可能配置不正确?有没有一种简单的方法可以访问我想要的视图控制器(在本例中为 Page1ViewController)。

【问题讨论】:

【参考方案1】:

我建议使用委托模式来解决您的问题。创建属性

@property (nonatomic, assign) id <MyModalViewDelegate> delegate;

以及相应的协议

@protocol MyModalViewDelegate
@optional
    - (void)myModalViewControllerDidFinish:(MyModalViewController *)aModalViewController;
@end

当用户完成您的视图时(例如点击保存按钮),发送此消息:

if ([self.delegate respondsToSelector:@selector(myModalViewControllerDidFinish:)])
    [self.delegate myModalViewControllerDidFinish:self];

现在,将委托设置为应该管理整个事情的视图控制器,当视图控制器完成时它会收到通知。请注意,您需要您的视图控制器来关闭模态视图控制器。但是,从逻辑上讲,这是有道理的,因为它是首先呈现模态视图控制器的对象。

这就是 Apple 在 UIImagePickerController 和 UIPersonPickerController 中解决此问题的方法。

【讨论】:

【参考方案2】:

有几种方法可以解决这个问题。最简单的可能就是在 myModalViewController 中添加一个 UIViewController 属性,并在呈现之前将其设置为 page1Controller:

myModalViewController.logicalParent = self; //page1Controller
[self presentModalViewController:myModalViewController animated:YES];

只需确保将适当的实例变量@property 和用于logicalParent 的@synthesize 添加到myModalViewController,然后您就可以将数据传回触发模态对话框的ViewController。这也适用于在不同导航级别之间来回传递数据,然后再将它们推送和弹出堆栈。

这样做时要担心的一件重要事情是,如果您不小心,很容易获得保留循环。根据您的具体结构,您可能需要使用分配属性。

【讨论】:

完全符合我的要求,谢谢!我是 Cocoa 的新手,但不是 MVC 的新手。但问题是,作为一名 Java Web 开发人员,我几乎总是忘记“C”中的控制器可以相互交互! 一个很好的答案,但为什么会这样呢?很明显不是模态视图的 parentViewController 是任何逻辑意义上的导航控制器(page1Controller 是要求模态显示的控制器),那么为什么 Cocoa Touch 会这样设置呢? 【参考方案3】:

我刚刚遇到了同样的问题。显然,如果您将 UIViewController 嵌入到 NavigationController 中,那么当您从该 UIViewController 以模态方式呈现另一个 UIViewController 时,演示者认为演示者是 NavigationController。也就是说,parentViewController 不正确。

我敢打赌这是一个错误:要么是这样,要么文档似乎不完整。我去问问。

【讨论】:

【参考方案4】:

刚刚遇到了同样的问题。我相信这是一个错误。我的情况如下: 按此顺序具有 A、B 和 C 视图控制器的导航层次结构。在 C 上,有一个按钮可以打开一个名为 D 的模式视图控制器。一旦呈现 D,导航控制器就会从其层次结构中删除 C,这是一种可怕的行为。一旦 D 被解除,导航控制器实例化一个新的 C 类型视图控制器并将其推入其层次结构以恢复原始视图控制器。糟糕的。我的解决方案是以这种方式破解导航层次结构(一个非常糟糕的解决方案,但效果很好。使用二维数组,您可以实现堆叠模式):

- (void)presentModalViewController:(UIViewController *)c 
    [self.navigationHierarchy removeAllObjects];
    [self.navigationHierarchy addObjectsFromArray:[navigation viewControllers]];
    [navigation setViewControllers:[NSArray array] animated:YES];
    [navigation presentModalViewController:c animated:YES];


- (void)dismissModalViewController 
    [navigation dismissModalViewControllerAnimated:YES];
    [navigation setViewControllers:[NSArray arrayWithArray:self.navigationHierarchy] animated:YES];

这两个方法是在我维护主要导航层次结构的地方定义的:应用程序委托。导航和导航层次结构是这样定义的:

NSMutableArray *navigationHierarchy;
UINavigationController *navigation;

【讨论】:

以上是关于parentViewController 总是导航控制器吗?的主要内容,如果未能解决你的问题,请参考以下文章

使用导航关闭模态视图控制器

自动将事件从 ChildViewController 传递到 parentViewController

如何从子视图访问 ParentViewController 方法?

对 ParentViewController 的开始/结束外观转换的不平衡调用

UIViewController 没有带有 UIModalPresentationFormSheet 的 parentViewController?

如何将触摸事件传递给 parentViewController?