首页 > 代码库 > addChildViewController时viewDidAppear方法得不到调用的问题
addChildViewController时viewDidAppear方法得不到调用的问题
今天遇到一个无比诡异的问题,原因在于viewDidLoad方法得到调用,而viewDidAppear方法得不到调用,导致viewDidAppear方法中的代码得不到执行。
下面写了个Demo,完整地模拟了这个场景。
首先是一个简单的故事板,其中AppDelegate的keyWindow是window,window的rootViewController是一个UINavigationController。如下:
NavigationController的rootViewController是ViewController。
ViewController上的Add按钮用于Add一个ChildViewController,其类为NewViewController类。
ViewController上的Remove按钮将之前Add上去的ChildViewController移除。
下面是ViewController类的代码:
#import "ViewController.h" #import "NewViewController.h" #import "AppDelegate.h" @interface ViewController () @property (strong, nonatomic) NewViewController *nvc; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } - (IBAction)addChild:(id)sender { UIWindow *keywindow = [UIApplication sharedApplication].keyWindow; UIViewController *controller = keywindow.rootViewController; NSLog(@"%@", controller); self.nvc = [NewViewController new]; [self.nvc willMoveToParentViewController:controller]; [controller addChildViewController:self.nvc]; self.nvc.view.frame = CGRectMake(100, 100, 100, 100); [controller.view addSubview:self.nvc.view]; [self.nvc didMoveToParentViewController:controller]; } - (IBAction)remove:(id)sender { [self.nvc.view removeFromSuperview]; [self.nvc removeFromParentViewController]; }
还有NewViewController类的代码:
#import "NewViewController.h" @implementation NewViewController - (void)viewDidLoad { [super viewDidLoad]; NSLog(@"viewDidLoad"); self.view.backgroundColor = [UIColor redColor]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; NSLog(@"viewDidAppear"); } @end
跑下Demo,点击Add,点击Remove,再点击Add,再点击Remove。
输出的Log如下:
2014-09-25 01:35:41.824 ParentVCDemo[24025:60b] <UINavigationController: 0x8c86aa0> 2014-09-25 01:35:41.826 ParentVCDemo[24025:60b] viewDidLoad 2014-09-25 01:35:43.232 ParentVCDemo[24025:60b] <UINavigationController: 0x8c86aa0> 2014-09-25 01:35:43.233 ParentVCDemo[24025:60b] viewDidLoad
可以看到keyWindow的rootViewController是一个UINavigationController类,在该controller上addChildViewController,也就是NewViewController类的一个实例。
明显NewViewController中的viewDidLoad方法是被调用的,而viewDidAppear方法是得不到调用的。
于是,如果你把设置NewViewController的view背景颜色为红色的代码放到viewDidAppear方法中的话,你将死活见不到一个红色的视图出现在屏幕中。
原因:在UINavigationController类或其子类对象上addChildViewController,将会导致Child View Controller中的viewDidAppear方法得不到执行。
建议:
1. 由于NewViewController被removeFromSuperview时,没有对象持有它,该对象将会被释放,那么下一次Add一个NewViewController时,其viewDidLoad方法必定会被调用,因此不用担心viewDidLoad方法只调用一次的问题,可以将viewDidAppear方法中的代码移到viewDidLoad方法中执行。
2. 获取正确的keyWindow,或者获取keyWindow中正确的controller,例如我们可以判断keyWindow的rootViewController是不是UINavigationController类或其子类,如果是的话,可以获取该导航控制器的topViewController。例如这样:
UIWindow *keywindow = [UIApplication sharedApplication].keyWindow; UIViewController *controller; if ([keywindow.rootViewController isKindOfClass:[UINavigationController class]]) { UINavigationController *naviController = (UINavigationController *)keywindow.rootViewController; controller = naviController.topViewController; } else { controller = keywindow.rootViewController; }
但是UITabBarController会不会受影响?还有没有更多的坑?不知道,实在是囧。
快两点了,晚安。就不骚扰某些人了,哈哈。
addChildViewController时viewDidAppear方法得不到调用的问题