ParentViewController 返回错误的父级
我正在从导航子视图 (ConnectionScreen) 中创建模式视图 (OnlinePeerBrowser)。我需要从模态视图的父视图引用方法。由于某种原因,模态视图认为它的父级是 rootView,而不是我创建模态的视图。
我做错了什么?
我创建模态视图的代码
@implementation ConnectionScreen {
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = @"ConnectionScreen";
}
return self;
}
...
- (void)peerPickerController:(GKPeerPickerController *)picker didSelectConnectionType:(GKPeerPickerConnectionType)type {
if (type == GKPeerPickerConnectionTypeOnline) {
OnlinePeerBrowser *controller = [[OnlinePeerBrowser alloc]
initWithNibName:@"OnlinePeerBrowser" bundle:nil];
[self presentModalViewController:controller animated:YES];
NSLog(@"my current view title: %@", [self title]);
NSLog(@"parent of the controller title: %@", [controller.parentViewController title]);
输出是:
my current view title: ConnectionScreen
parent of the controller title: Home
模态视图正在从 ConnectionScreen 实例中创建并呈现为 ModalViewController。为什么它使用根窗口作为父窗口?
------- 更多关于此 ---------- 我向苹果提交了一个错误,认为我很聪明;)。他们实际上发现了我的代码在推动导航控制器时存在问题(滚动到底部查看)。我不明白我做错了什么。他们还通过优雅地退出解决 API 更改来确保此类事情不会在 5.0 中发生,如下文尼所述。
如果有人能通过下面的视图看到我做错了什么,我将不胜感激。 ------- 更多关于此 ----------
在提交有关 iOS 开发的 ModalViewController 的错误报告后,刚刚收到 Apple 的回复。我正在尝试解读他们的反应。 (请注意,支持回复说是机密。由于你们都是注册的 Apple 开发人员,所以我认为分享是可以的。)
从下面的回复中,我无法判断他们是否在说我创建导航控制器的方法和推送根视图是错误的,或者如果他们承认该错误并声明他们在 iOS 5 中对此进行了协调。
这是我提交的重复“错误”的代码。
对我提交的错误的响应:
错误标题:模态视图的父级不正确
重现步骤: 创建导航控制器 推送标题为“Home”的视图控制器 在“Home”视图控制器上创建一个按钮,用于推送另一个视图控制器“NewView” 在“NewView”上创建一个拉出模态视图的按钮 在该模式视图中调用 self.parentViewController.title
预期与实际结果: 模态视图的父标题应该是NewView;但是,它显示模态视图的父视图是 Home。
笔记: 我的解决方法是在使模态视图可见之前在模态视图 myParent 上设置一个属性。
他们的响应
工程已根据以下信息确定此问题的行为符合预期:
此测试应用程序将在 5.0 中退出并出现 UIViewControllerHierarchyInconsistency。 applicationDidFinishLaunching 方法是高度可疑的异常(也是 5.0 的原因)。窗口的根视图控制器被推送为视图控制器的子级,然后该视图控制器的视图将添加到窗口中。
这可能会导致各种不一致,因此我们现在在 5.0 上提出这个问题。请注意,在 5.0 中,parentViewController 不再返回模式呈现器。我们添加了presentingViewController 方法来覆盖这种情况。现在保留parentViewController来指示视图控制器之间的包含关系。
他们声称的代码是可疑的:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
self.navigationController = [[UINavigationController alloc] init];
self.window.rootViewController = self.viewController;
[self.navigationController pushViewController:self.window.rootViewController animated:NO];
// Add the navigation controller's view to the window and display.
[self.window addSubview:self.navigationController.view];
[self.window makeKeyAndVisible];
return YES;
}
I am creating a modal view (OnlinePeerBrowser) from within a navigation subview (ConnectionScreen). I need to reference methods from the parent view of the Modal view. For some reason, the modal view believes it's parent is the rootView and not the view I created the modal from.
What am I doing wrong?
My code to create the modal view
@implementation ConnectionScreen {
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = @"ConnectionScreen";
}
return self;
}
...
- (void)peerPickerController:(GKPeerPickerController *)picker didSelectConnectionType:(GKPeerPickerConnectionType)type {
if (type == GKPeerPickerConnectionTypeOnline) {
OnlinePeerBrowser *controller = [[OnlinePeerBrowser alloc]
initWithNibName:@"OnlinePeerBrowser" bundle:nil];
[self presentModalViewController:controller animated:YES];
NSLog(@"my current view title: %@", [self title]);
NSLog(@"parent of the controller title: %@", [controller.parentViewController title]);
The output is:
my current view title: ConnectionScreen
parent of the controller title: Home
The modal view is being created and presented as a ModalViewController from within a ConnectionScreen instance. Why is it using the root window as the parent?
------- More on this -----------
I filed a bug with Apple thinking I was smart ;). They actually identified an issue with my code with pushing the nav controller (Scroll to bottom to see). I don't see what am I doing wrong. They also made sure this type of thing doesn't happen in 5.0 with gracefully exiting addressing an API change as Vinnie states below.
If anyone can see what I am doing wrong with the view pushing below, I would appreciate it.
------- More on this -----------
just received a response from Apple after filing a bug report on the ModalViewController for iOS development. I am trying to deciper their response.
(Note the support response says confidential. Since you are all registered Apple developers, I thought it would be ok to share.)
From the response below, I can't tell if they are they saying that my approach to creating the navigation controller and pushing the root view is wrong, or if they admitting to the bug and stating that they reconciled this in iOS 5.
Here is the code I submitted to repeat the 'bug'.
The response to the bug I filed:
Bug Title: Modal view has the incorrect parent
Steps to Reproduce:
Create a navigation controller
Push a view controller with the title 'Home'
Create a button on the 'Home' view controller that pushes another view controller 'NewView'
On 'NewView' create a button that pulls up a modal view
In that modal view call self.parentViewController.title
Expected vrs Actual Results:
The parent title of the modal view should be NewView; however, it shows that the parent view of the modal view is Home.
Notes:
My workaround is to set a property on the modal view, myParent, prior to making the modal view visible.
Their response
Engineering has determined that this issue behaves as intended based on the following information:
This test application will exit with a UIViewControllerHierarchyInconsistency in 5.0. The applicationDidFinishLaunching method is highly suspect (and the cause of the 5.0) exception. The window's root view controller is being pushed as the child of a view controller whose view is then added to the window.
This is likely causing of all sorts of inconsistencies, hence why we now raise the issue on 5.0. Note that in 5.0, parentViewController no longer returns the modal presenter. We added the method presentingViewController to cover this case. parentViewController is now reserved to indicate a containment relationship between view controllers.
The code they claim is suspect:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
self.navigationController = [[UINavigationController alloc] init];
self.window.rootViewController = self.viewController;
[self.navigationController pushViewController:self.window.rootViewController animated:NO];
// Add the navigation controller's view to the window and display.
[self.window addSubview:self.navigationController.view];
[self.window makeKeyAndVisible];
return YES;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果在 iOS 5 中对此进行测试,您将获得该属性的错误值。从 iOS 5 开始,调用presentModalViewController 时不再设置parentViewController。相反,您必须使用presentingViewController 属性。但是,如果您支持其他版本的 iOS,则需要稍微花点心思。要么做一些这样的检查:
您还可以设置自己的委托或创建一些 customParentViewController 属性来确定。我个人就走了这条路。
有些人只是想调用[self.parentViewController解雇ModalViewController]。在这种情况下,请使用 [selfmissModalViewController],因为它只会为您爬上堆栈并自行关闭。
是的,任何用 iOS 4 及更低版本编写的代码现在都已在 iOS 5 设备上被破坏,因此请检查应用程序商店中的其他应用程序。
If testing this in iOS 5, you're going to get the incorrect value for this property. As of iOS 5, parentViewController is no longer set when presentModalViewController is called. Instead, you will have to use the presentingViewController property. If however, you are supporting other versions of iOS, you will have to get slightly fancy. Either do some checking like this:
You could also set your own delegate or create some customParentViewController property to be sure. I personally went this route.
Some people just want to call [self.parentViewController dismissModalViewController]. In that case, use [self dismissModalViewController] because it will just climb up the stack for you and dismiss itself.
And yes, any code written in iOS 4 and below has now been broken on iOS 5 devices so check your other apps in the app store.
这些都在同一个函数内,因此所有代码都会同时运行。您说应用程序在 UI 方面运行正常,因此 NSLogs 确实应该放置在 OnlinePeerBrowser 的 viewDidLoad 函数中。然后它应该可以正常工作。
This is all within the same function, so ALL of the code is run at the same time. You said that the app is functioning normally UI wise, so the NSLogs should really be placed in the viewDidLoad function of OnlinePeerBrowser. Then it should work properly.