ios - subview UINavigationController 泄漏 ARC

标签 ios objective-c memory-leaks uinavigationcontroller

在 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创建了一个简单的测试应用程序,

enter image description here

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/

相关文章:

ios - 如何在 ios 中从暂停继续播放歌曲

google-chrome - 取消缩小 chrome 的堆快照

java - 什么是类加载器泄漏?

javascript - 从其他组件使用 setState 调用函数

ios - 为什么即使我从后台杀死了 foursquare,位置图标仍然存在

objective-c - 格式数字字符串,到许多尾随/数字/零

c++ - 如何将文件中的字节提取为简单的数据类型?

objective-c - NSURLConnection 泄漏?

ios - 自定义元素的子层不在模拟器中渲染,在界面生成器中渲染

ios - 在 swift : Difference between Array VS NSArray VS [AnyObject]