iOS11+Xcode9添加子ViewController时崩溃求助
我来帮你拆解这个崩溃问题——这是Xcode9(对应iOS11)之后UIKit对容器控制器的校验变严格导致的典型问题,先看核心崩溃信息:
-[NavigationViewController _viewControllerSubtreeDidGainViewController:]: unrecognized selector sent to instance 0x7f91ba83c000
这个_viewControllerSubtreeDidGainViewController:是UIKit给**标准容器视图控制器(比如UINavigationController、UITabBarController)**预留的私有方法,当你调用addChildViewController:时,系统会默认把目标控制器当作容器控制器来处理,尝试调用这类方法。但你的NavigationViewController是继承自普通的UIViewController,并没有实现这些容器相关的方法,所以直接崩溃了——之前的Xcode版本可能没有做这么严格的检查,所以能正常运行。
你的代码问题根源
你写的NavigationViewController本质是一个包装了UINavigationController的普通ViewController,但你把它当作子控制器添加时,系统误以为它是标准容器,触发了未实现的私有方法调用。
两种可行修复方案
方案1:直接继承UINavigationController(推荐)
如果你的需求是自定义导航控制器的行为,完全没必要自己包装一个UINavigationController,直接继承系统的UINavigationController就好,这样系统自带的容器方法都会自动实现,完美适配Xcode9+的校验:
// 修改NavigationViewController的头文件继承 @interface NavigationViewController : UINavigationViewController <UINavigationControllerDelegate> @end // 实现文件调整 @implementation NavigationViewController - (id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (!self) return nil; self.edgesForExtendedLayout = UIRectEdgeAll; self.navigationBarHidden = YES; self.view.clipsToBounds = YES; self.view.backgroundColor = [UIColor clearColor]; self.delegate = self; // 若需要自定义导航逻辑,记得遵守UINavigationControllerDelegate协议 return self; } @end
这样你原来的_navController就可以完全移除,直接复用系统导航控制器的所有功能,也符合苹果的设计规范。
方案2:手动管理子控制器生命周期(不推荐,仅当无法修改继承关系时用)
如果必须让NavigationViewController继承自UIViewController,那不要用addChildViewController:添加它,而是直接把它的视图加到父视图中,手动管理生命周期:
// 在添加_mainSectionsController的地方修改 _mainSectionsController = [[[MainSectionsController alloc] initWithNibName:nil bundle:nil] autorelease]; // 不要调用addChildViewController,改用手动生命周期管理 [self.view addSubview:_mainSectionsController.view]; [_mainSectionsController didMoveToParentViewController:self];
这种方式需要你手动处理所有容器控制器的生命周期方法(比如willMoveToParentViewController:),容易出现视图层级或生命周期的问题,所以优先选方案1。
额外提醒
Xcode9之后,UIKit对容器控制器的生命周期校验大幅收紧,很多之前“不规范但能跑”的写法都会触发崩溃。如果需要自定义容器控制器,一定要遵循苹果的官方规范,要么继承系统的容器类,要么完整实现容器控制器的所有必要方法(不推荐触碰私有方法)。
内容的提问来源于stack exchange,提问作者umj

