子视图控制器在呈现和关闭模态视图后失去委托
Child View Controller loses delegate after Presenting and Dismissing Modal View
我正在使用此代码添加子视图控制器:
MyCustomViewController * overlayView = [[MyCustomViewController alloc] initWithNibName:@"MyCustom" bundle:nil];
UIViewController *parentViewController = self.tabBarController;
[modalView willMoveToParentViewController:parentViewController];
// set the frame for the overlayView
overlayView.view.frame = parentViewController.view.frame;
[parentViewController.view addSubview: overlayView.view];
[parentViewController.view needsUpdateConstraints];
[parentViewController.view layoutIfNeeded];
// Finish adding the overlayView as a Child View Controller
[parentViewController addChildViewController: overlayView];
[overlayView didMoveToParentViewController:parentViewController];
然后在 MyCustomViewController
内点击一个按钮会触发一个模态视图:
MyModalViewController *vc = [[MyModalViewController alloc] initWithNibName:@"DirectEmployerSignup" bundle:nil];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:vc];
UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithTitle:@"Close" style:UIBarButtonItemStylePlain target:self action:@selector(closeTheModal:)];
vc.navigationItem.leftBarButtonItem = button;
[self.navigationController presentViewController:navigationController animated:YES completion:nil];
点击 UIBarButtonItem
触发 closeTheModal:
- (void)closeTheModal:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
模式关闭后,MyCustomViewController
仍然可见,但视图停止按预期做出反应。 MyCustomViewController
上的 UITextViews
不会触发 MyCustomViewController.m
等中的委托方法
为了清楚起见:我仍然可以点击 MyCustomViewController
上的 UITextFields
,并且仍然可以看到按钮在我点击它们时有反应,但是它们未触发其关联 IBActions
等
如果您对正在发生的事情有任何想法,我们将不胜感激。
附加信息
我添加了一个关闭模态的方法,使用 MyModalViewController
中的 [self.navigationController dismissViewControllerAnimated:YES completion:nil];
并将 action:@selector()
指向该方法。
MyModalViewController
中的方法触发并关闭了模式,但 MyCustomViewController
仍然没有响应。
po [[[[UIApplication sharedApplication] keyWindow] rootViewController] _printHierarchy]
当我 运行 po [[[[UIApplication sharedApplication] keyWindow] rootViewController] _printHierarchy]
,在模态视图出现之前,我看到了这个:
<UINavigationController 0x7fc23985b200>, state: appeared, view: <UILayoutContainerView 0x7fc238f3b760>
| <MyTabBarController 0x7fc23a045400>, state: appeared, view: <UILayoutContainerView 0x7fc238cc7500>
| | <MyNavigationController 0x7fc23985a800>, state: appeared, view: <UILayoutContainerView 0x7fc23b0497e0>
| | | <FirstTabViewController 0x7fc238d47650>, state: appeared, view: <UIView 0x7fc23b1318a0>
| | <UINavigationController 0x7fc23a0bc000>, state: disappeared, view: (view not loaded)
| | | <SecondTabViewController 0x7fc238c8da90>, state: disappeared, view: (view not loaded)
| | <UINavigationController 0x7fc23987c800>, state: disappeared, view: (view not loaded)
| | | <ThirdTabViewController 0x7fc238f77c00>, state: disappeared, view: (view not loaded)
| | <MyCustomViewController 0x7fc238d48e50>, state: appearing, view: <UIView 0x7fc23b086220>
但是...在我关闭模态框并重新运行 po [[[[UIApplication sharedApplication] keyWindow] rootViewController] _printHierarchy]
后,<MyCustomViewController 0x7fc238d48e50>
不见了。
也许问题源于 <MyCustomViewController>
说 "appearing" 而没有说 "appeared"?
我的解决方案
我从
更改为 MyCustomViewController
UIViewController *parentViewController = self.tabBarController;
至
UIViewController *parentViewController = self.tabBarController.navigationController;
感谢所有提供帮助的人。我会重新审视你的答案,希望下次能把这个效果做得更好。
您需要确保在模态中关闭 navigationController
...否则它只是关闭内部控制器(不是它的父级!)并且仍然存在(并拦截您的事件)
- (void)closeTheModal:(id)sender {
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
此问题是由于您的 MyCustomViewController
已从其父控制器中删除所致。届时您的活动将停止传送。
根据您发布的代码,我不能说是什么导致控制器被删除,但您应该能够使用 -[MyCustomViewController removeFromParentViewController]:
中的断点很容易地调试它。您要么是错误地明确删除了它,要么是 UITabBarController
自行删除(可能是由下述问题引起的)。
但是,还有一个大问题:
UITabBarController
是一个容器控制器。控制器的全部意义在于管理其子视图控制器。这也意味着控制器正在管理哪个控制器正在接收外观回调(例如 viewWillAppear:
、viewDidAppear:
等)。通过添加另一个子视图控制器,您正在做一些不受支持的事情。
例如,当UITabBarController
出现时,它只发送viewDidAppear:
到它选择的控制器。它不会将 viewDidAppear:
发送到您的附加控制器。
这会导致许多非常有问题的状态,我认为这是您问题的根源。
与其将子控制器直接添加到 UITabBarController
,您可以考虑以下层次结构(为选项卡栏控制器和您的自定义控制器引入一个公共父级)。
UIViewController
| UITabBarController
| MyCustomViewController
您的问题出在这段代码中
MyModalViewController *vc = [[MyModalViewController alloc] initWithNibName:@"DirectEmployerSignup" bundle:nil];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:vc];
UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithTitle:@"Close" style:UIBarButtonItemStylePlain target:self action:@selector(closeTheModal:)];
vc.navigationItem.leftBarButtonItem = button;
[self.navigationController presentViewController:navigationController animated:YES completion:nil];
当您声明时,
UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithTitle:@"Close" style:UIBarButtonItemStylePlain target:self action:@selector(closeTheModal:)];
vc.navigationItem.leftBarButtonItem = button;
目标集是 self
,正如您在 MyCustomViewController
中声明的那样,自身将是一个 MyCustomViewController
实例。并且可能您已经在同一个 class 中声明了选择器 closeTheModal
。因此用 self 释放的实例可能是 MyCustomViewController
insatnce.
这样做,
UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithTitle:@"Close" style:UIBarButtonItemStylePlain target:**vc** action:@selector(closeTheModal:)];
vc.navigationItem.leftBarButtonItem = button;
并在 MyModalViewController
中声明选择器 class 并检查。
我正在使用此代码添加子视图控制器:
MyCustomViewController * overlayView = [[MyCustomViewController alloc] initWithNibName:@"MyCustom" bundle:nil];
UIViewController *parentViewController = self.tabBarController;
[modalView willMoveToParentViewController:parentViewController];
// set the frame for the overlayView
overlayView.view.frame = parentViewController.view.frame;
[parentViewController.view addSubview: overlayView.view];
[parentViewController.view needsUpdateConstraints];
[parentViewController.view layoutIfNeeded];
// Finish adding the overlayView as a Child View Controller
[parentViewController addChildViewController: overlayView];
[overlayView didMoveToParentViewController:parentViewController];
然后在 MyCustomViewController
内点击一个按钮会触发一个模态视图:
MyModalViewController *vc = [[MyModalViewController alloc] initWithNibName:@"DirectEmployerSignup" bundle:nil];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:vc];
UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithTitle:@"Close" style:UIBarButtonItemStylePlain target:self action:@selector(closeTheModal:)];
vc.navigationItem.leftBarButtonItem = button;
[self.navigationController presentViewController:navigationController animated:YES completion:nil];
点击 UIBarButtonItem
触发 closeTheModal:
- (void)closeTheModal:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
模式关闭后,MyCustomViewController
仍然可见,但视图停止按预期做出反应。 MyCustomViewController
上的 UITextViews
不会触发 MyCustomViewController.m
等中的委托方法
为了清楚起见:我仍然可以点击 MyCustomViewController
上的 UITextFields
,并且仍然可以看到按钮在我点击它们时有反应,但是它们未触发其关联 IBActions
等
如果您对正在发生的事情有任何想法,我们将不胜感激。
附加信息
我添加了一个关闭模态的方法,使用 MyModalViewController
中的 [self.navigationController dismissViewControllerAnimated:YES completion:nil];
并将 action:@selector()
指向该方法。
MyModalViewController
中的方法触发并关闭了模式,但 MyCustomViewController
仍然没有响应。
po [[[[UIApplication sharedApplication] keyWindow] rootViewController] _printHierarchy]
当我 运行 po [[[[UIApplication sharedApplication] keyWindow] rootViewController] _printHierarchy]
,在模态视图出现之前,我看到了这个:
<UINavigationController 0x7fc23985b200>, state: appeared, view: <UILayoutContainerView 0x7fc238f3b760>
| <MyTabBarController 0x7fc23a045400>, state: appeared, view: <UILayoutContainerView 0x7fc238cc7500>
| | <MyNavigationController 0x7fc23985a800>, state: appeared, view: <UILayoutContainerView 0x7fc23b0497e0>
| | | <FirstTabViewController 0x7fc238d47650>, state: appeared, view: <UIView 0x7fc23b1318a0>
| | <UINavigationController 0x7fc23a0bc000>, state: disappeared, view: (view not loaded)
| | | <SecondTabViewController 0x7fc238c8da90>, state: disappeared, view: (view not loaded)
| | <UINavigationController 0x7fc23987c800>, state: disappeared, view: (view not loaded)
| | | <ThirdTabViewController 0x7fc238f77c00>, state: disappeared, view: (view not loaded)
| | <MyCustomViewController 0x7fc238d48e50>, state: appearing, view: <UIView 0x7fc23b086220>
但是...在我关闭模态框并重新运行 po [[[[UIApplication sharedApplication] keyWindow] rootViewController] _printHierarchy]
后,<MyCustomViewController 0x7fc238d48e50>
不见了。
也许问题源于 <MyCustomViewController>
说 "appearing" 而没有说 "appeared"?
我的解决方案 我从
更改为MyCustomViewController
UIViewController *parentViewController = self.tabBarController;
至
UIViewController *parentViewController = self.tabBarController.navigationController;
感谢所有提供帮助的人。我会重新审视你的答案,希望下次能把这个效果做得更好。
您需要确保在模态中关闭 navigationController
...否则它只是关闭内部控制器(不是它的父级!)并且仍然存在(并拦截您的事件)
- (void)closeTheModal:(id)sender {
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
此问题是由于您的 MyCustomViewController
已从其父控制器中删除所致。届时您的活动将停止传送。
根据您发布的代码,我不能说是什么导致控制器被删除,但您应该能够使用 -[MyCustomViewController removeFromParentViewController]:
中的断点很容易地调试它。您要么是错误地明确删除了它,要么是 UITabBarController
自行删除(可能是由下述问题引起的)。
但是,还有一个大问题:
UITabBarController
是一个容器控制器。控制器的全部意义在于管理其子视图控制器。这也意味着控制器正在管理哪个控制器正在接收外观回调(例如 viewWillAppear:
、viewDidAppear:
等)。通过添加另一个子视图控制器,您正在做一些不受支持的事情。
例如,当UITabBarController
出现时,它只发送viewDidAppear:
到它选择的控制器。它不会将 viewDidAppear:
发送到您的附加控制器。
这会导致许多非常有问题的状态,我认为这是您问题的根源。
与其将子控制器直接添加到 UITabBarController
,您可以考虑以下层次结构(为选项卡栏控制器和您的自定义控制器引入一个公共父级)。
UIViewController
| UITabBarController
| MyCustomViewController
您的问题出在这段代码中
MyModalViewController *vc = [[MyModalViewController alloc] initWithNibName:@"DirectEmployerSignup" bundle:nil];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:vc];
UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithTitle:@"Close" style:UIBarButtonItemStylePlain target:self action:@selector(closeTheModal:)];
vc.navigationItem.leftBarButtonItem = button;
[self.navigationController presentViewController:navigationController animated:YES completion:nil];
当您声明时,
UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithTitle:@"Close" style:UIBarButtonItemStylePlain target:self action:@selector(closeTheModal:)];
vc.navigationItem.leftBarButtonItem = button;
目标集是 self
,正如您在 MyCustomViewController
中声明的那样,自身将是一个 MyCustomViewController
实例。并且可能您已经在同一个 class 中声明了选择器 closeTheModal
。因此用 self 释放的实例可能是 MyCustomViewController
insatnce.
这样做,
UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithTitle:@"Close" style:UIBarButtonItemStylePlain target:**vc** action:@selector(closeTheModal:)];
vc.navigationItem.leftBarButtonItem = button;
并在 MyModalViewController
中声明选择器 class 并检查。