Container UIViewController不释放它的子视图控制器

mik*_*dev 14 uiviewcontroller ios automatic-ref-counting

我有一个自定义容器UIViewController,它有六个子UIViewControllers,以及一组用户与之交互以在子视图控制器之间切换的选项卡.问题是当我的容器视图控制器被释放时,子视图控制器不是.

我已经验证通过向dealloc方法添加一些调试代码而不释放子视图控制器,只要它们的视图没有添加到容器视图控制器的视图中,它们就会被释放.

下面是我用来创建自定义容器视图控制器的代码的摘录.viewController指针是iVars.我也在使用ARC,这就是为什么没有实际的发布调用.

- (void)init 
{
    if ((self = [super init])) { 
        vc1 = [[UIViewController alloc] init];
        [self addChildViewController:vc1];

        vc2 = [[UIViewController alloc] init];
        [self addChildViewController:vc2];

        vc3 = [[UIViewController alloc] init];
        [self addChildViewController:vc3];

        vc4 = [[UIViewController alloc] init];
        [self addChildViewController:vc4];

        vc5 = [[UIViewController alloc] init];
        [self addChildViewController:vc5];

        vc6 = [[UIViewController alloc] init];
        [self addChildViewController:vc6];
    }
    return self;
}

- (void)dealloc
{
    [vc1 removeFromParentViewController];
    vc1 = nil;

    [vc2 removeFromParentViewController];
    vc2 = nil;

    [vc3 removeFromParentViewController];
    vc3 = nil;

    [vc4 removeFromParentViewController];
    vc4 = nil;

    [vc5 removeFromParentViewController];
    vc5 = nil;

    [vc6 removeFromParentViewController];
    vc6 = nil;
}

- (void)switchFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController
{
    if (fromViewController) {
        [fromViewController.view removeFromSuperview];
    }

    [self.view addSubview:toViewController];
    toViewController.view.frame = self.view.bounds;
}
Run Code Online (Sandbox Code Playgroud)

你们有什么想法我做错了吗?

Sri*_*nth 26

这不是添加和删除子视图控制器的方法

    [childViewController willMoveToParentViewController:nil];
    [childViewController view] removeFromSuperview];
    [childViewController removeFromParentViewController];
Run Code Online (Sandbox Code Playgroud)

是删除和添加它的方法

    [parentViewController addChildViewController:childViewController];
    [parentViewController.view addSubview:childViewController.view];
    [childViewController didMoveToParentViewController:parentViewController];
Run Code Online (Sandbox Code Playgroud)

  • 删除代码中的第二行缺少初始值[ (2认同)

Rob*_*Rob 12

我怀疑,问题与问题中的视图控制器包含代码无关,而是您添加了观察者(您在回答此问题时讨论):

[[NSNotificationCenter defaultCenter] addObserverForName:kUpdateEventName object:nil queue:nil usingBlock:^(NSNotification *note) {
    // do stuff when update happen
}];
Run Code Online (Sandbox Code Playgroud)

而你试图删除它

[[NSNotificationCenter defaultCenter] removeObserver:self name:kUpdateEventName object:nil];
Run Code Online (Sandbox Code Playgroud)

所以,有两个问题:

  1. 如果使用addObserverForName:object:queue:,这不是删除此观察者的正确方法.相反,定义一个属性来跟踪观察者:

    @property (nonatomic, weak) id<NSObject> notification;
    
    Run Code Online (Sandbox Code Playgroud)

    然后在创建时保存对该观察者的引用:

    self.notification = [[NSNotificationCenter defaultCenter] addObserverForName:kUpdateEventName object:nil queue:nil usingBlock:^(NSNotification *note) {
        // do something
    }];
    
    Run Code Online (Sandbox Code Playgroud)

    如果要删除它,请使用以下参考:

    [[NSNotificationCenter defaultCenter] removeObserver:self.notification];
    
    Run Code Online (Sandbox Code Playgroud)

    这将确保观察员得到适当的移除.

  2. 在此观察者到位时释放子视图控制器失败意味着您传递给的此块addObserverForName:object:queue:必须具有引用self.如果您试图正确删除此观察者(如上所示)dealloc,您仍然会有一个强大的参考周期(以前称为保留周期).这可以通过多种方式解决,但最强大的模式是通过使用weakSelf模式首先防止强引用循环:

    typeof(self) __weak weakSelf = self;
    
    self.notification = [[NSNotificationCenter defaultCenter] addObserverForName:kFooNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
        // use `weakSelf` in this block; not `self`
    }];
    
    Run Code Online (Sandbox Code Playgroud)

我原来的答案如下:


虽然Srikanth之后是正确的addChildViewController,你应该打电话didMoveToParentViewController:self,然后removeFromParentViewController再打电话willMoveToParentViewController:nil.但那不是你的问题.事实上,我使用了你的代码的变体(即使没有dealloc),并且子控制器被释放得很好.

最重要的是,我怀疑你的问题在别处,可能是某个地方的保留周期.例如,您的孩子是否有强烈的父母参考?你在使用定期计时器吗?您引用一些选项卡.您没有使用标签栏控制器,是吗?它必须是那样的.

[如果您想查看原始答案的其余部分,请参阅修订历史记录,其中包含代码片段和OP代码示例的次要详细信息]