在 subview 中呈现和关闭 UINavigationController 时,我遇到内存泄漏(UINavigationController 及其 Root View Controller 都被泄漏)。我介绍导航 Controller 的方法似乎有点不标准,所以我希望 SO 社区中的某个人能够提供帮助。
<强>1。介绍
导航 Controller 呈现如下:
-(void) presentSubNavigationControllerWithRootViewControllerIdentifier:(NSString *)rootViewControllerIdentifier inStoryboardWithName:(NSString *)storyboardName {
// grab the root view controller from a storyboard
UIStoryboard * storyboard = [UIStoryboard storyboardWithName:storyboardName bundle:nil];
UIViewController * rootViewController = [storyboard instantiateViewControllerWithIdentifier:rootViewControllerIdentifier];
// instantiate the navigation controller
UINavigationController * nc = [[UINavigationController alloc] initWithRootViewController:rootViewController];
// perform some layout configuration that should be inconsequential to memory management (right?)
[nc setNavigationBarHidden:YES];
[nc setEdgesForExtendedLayout:UIRectEdgeLeft | UIRectEdgeRight | UIRectEdgeBottom];
nc.view.frame = _navControllerParentView.bounds;
// install the navigation controller (_navControllerParentView is a persisted IBOutlet)
[_navControllerParentView addSubview:nc.view];
// strong reference for easy access
[self setSubNavigationController:nc];
}
在这一点上,我的期望是导航 Controller 的唯一“所有者”是父 View Controller (在本例中为 self
)。但是,当如下所示关闭导航 Controller 时,它不会被释放(因此它的 rootViewController
也被泄露,依此类推所有权树)。
<强>2。解雇
Dismissal 非常简单,但似乎不足以进行适当的内存管理:
-(void) dismissSubNavigationController {
// prevent an orphan view from remaining in the view hierarchy
[_subNavigationController.view removeFromSuperview];
// release our reference to the navigation controller
[self setSubNavigationController:nil];
}
肯定是其他东西“保留”了导航 Controller ,因为它没有被释放。我不认为它可能是保留它的 Root View Controller ,对吧?
一些研究表明 retainCount
没有意义,但 FWIW 我已经确定它在解雇后保持在 2,我希望它为零。
是否有一种完全不同/更好的方法来呈现 subNavigationController?也许在 Storyboard中定义导航 Controller 比简单地消除对几行代码的需要有更大的好处?
最佳答案
当添加一个 Controller 的 View 作为另一个 Controller View 的 subview 时,最好的做法是让添加的 View 的 Controller 成为 subview Controller ;也就是说,您将其添加到其 View 的 Controller 应该实现自定义容器 Controller api。一个简单的设置方法是在 Storyboard 中使用容器 View ,它会自动为您提供一个嵌入式 Controller (您可以选择该 Controller ,然后在编辑菜单中选择嵌入导航 Controller 以获取您尝试的 UI制作)。通常,这个嵌入式 View Controller 会在父 Controller 的 View 加载后立即添加,但您可以通过实现 shouldPerformSegueWithIdentifier:sender: 来抑制它。我用这个 Storyboard创建了一个简单的测试应用程序,
ViewController 中用于抑制初始呈现的代码,以及随后呈现和关闭它的按钮方法如下,
@implementation ViewController
-(BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender {
if ([identifier isEqualToString:@"Embed"]) { // The embed segue in IB was given this identifier. This method is not called when calling performSegueWithIdentifier:sender: in code (as in the button method below)
return NO;
}else{
return YES;
}
}
- (IBAction)showEmbed:(UIButton *)sender {
[self performSegueWithIdentifier:@"Embed" sender:self];
}
- (IBAction)dismissEmbed:(UIButton *)sender {
[[self.childViewControllers.firstObject view] removeFromSuperview];
[self.childViewControllers.firstObject willMoveToParentViewController:nil];
[self.childViewControllers.firstObject removeFromParentViewController];
}
@end
当触摸 Dismiss 按钮时,导航 Controller 及其任何 subview Controller 都会被正确释放。
关于ios - subview UINavigationController 泄漏 ARC,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29216992/