容器UIViewController不释放它的子视图控制器 [英] Container UIViewController Not Releasing it's Child View Controllers

查看:695
本文介绍了容器UIViewController不释放它的子视图控制器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a custom container UIViewController that has six child UIViewControllers, and a set of tabs that the user interacts with to switch between the child view controllers. The problem is when my container view controller is released the child view controllers are not.

我已经通过在dealloc方法中添加一些调试代码来验证子视图控制器没有被释放,并且只要它们的视图没有被添加到容器视图控制器的视图。

I have verified that the child view controllers are not released by adding some debugging code to their dealloc methods, and they are released as long as their view's are not added to the container view controller's view.

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

Below is an a excerpt of the code I'm using to create my custom container view controller. The viewController pointers are iVars. I am also using ARC so that is why there are no actual release calls.

- (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;
}

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

Do you all have any ideas what I'm doing wrong?

推荐答案

正如我所怀疑的那样,问题与问题中的视图控制器包含代码无关,而是与观察者的添加有关(你在这个问题的答案中讨论):

As I suspected, the problem is not related to the view controller containment code in the question, but rather your adding of the observers (which you discuss in your answer to this question):

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

您尝试将其删除

[[NSNotificationCenter defaultCenter] removeObserver:self name:kUpdateEventName object:nil];

所以,有两个问题:


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

  1. If you use addObserverForName:object:queue:, this is not the correct way to remove this observer. Instead, define a property to keep track of the observer:

@property (nonatomic, weak) id<NSObject> notification;

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

Then save a reference to that observer when you create it:

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

如果你想删除它,请使用此引用:

And when you want to remove it, use this reference:

[[NSNotificationCenter defaultCenter] removeObserver:self.notification];

这样可以确保正确删除观察者。

That would ensure that the observer would be removed properly.

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

The failure of the child view controllers to be released while this observer was in place means that this block that you passed to addObserverForName:object:queue: must of had a reference to self. If you tried to remove this observer correctly (as shown above) in dealloc, you would still have a strong reference cycle (formerly known as a retain cycle). This is resolved in a number of ways, but the most robust pattern is to prevent the strong reference cycle in the first place by using the weakSelf pattern:

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`
}];







我的原始答案如下:


My original answer is below:

虽然Srikanth在 addChildViewController ,你应该调用 didMoveToParentViewController:self ,在 removeFromParentViewController 之前你应该调用 willMoveToParentViewController :无。但那不是你的问题。事实上,我使用了你的代码的变体(即使没有 dealloc ),并且子控制器被释放了。

While Srikanth is right that after addChildViewController, you should call didMoveToParentViewController:self and before removeFromParentViewController you should call willMoveToParentViewController:nil. But that's not your problem. In fact, I used a variation of your code (even without the dealloc), and the children controllers are released fine.

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

Bottom line, I suspect your problem rests elsewhere, probably a retain cycle somewhere. For example, do you children have strong reference to the parent? Are you using recurring timers? You reference some tabs. You're not using a tab bar controller, are you? It's got to be something like that.

[如果您想查看原始答案的其余部分,请参阅修订历史记录以及OP代码示例的详细信息]

[Refer to revision history if you want to see rest of the original answer with code snippets and minor details on the OP's code sample]

这篇关于容器UIViewController不释放它的子视图控制器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆