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

我有一个自定义的容器UIViewController有六个子UIViewControllers和一组用户交互切换子视图控制器的选项卡。 问题是当我的容器视图控制器被释放子视图控制器不是。

我已经validation了子视图控制器不是通过向它们的dealloc方法添加一些debugging代码来释放的,只要它们的视图没有被添加到容器视图控制器的视图中,它们就被释放。

下面是我用来创build我的自定义容器视图控制器的代码摘录。 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; } 

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

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

 [[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:这不是删除此观察者的正确方法。 相反,定义一个属性来跟踪观察者:

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

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

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

    而当你想删除它,使用这个参考:

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

    这将确保观察员将被正确移除。

  2. 当这个观察者就位时,子视图控制器的失败意味着你传递给addObserverForName:object:queue: must的这个块有一个对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` }]; 

我的原始答案如下:


虽然Srikanth是正确的, addChildViewController后,你应该调用didMoveToParentViewController:selfremoveFromParentViewController之前,你应该调用willMoveToParentViewController:nil 。 但这不是你的问题。 事实上,我使用了你的代码的变体(即使没有dealloc ),孩子们的控制器释放正常。

底线,我怀疑你的问题在别处,可能是一个保留周期的地方。 例如,你的孩子有没有强烈的参考父母? 你使用循环定时器吗? 你引用一些标签。 你没有使用标签栏控制器,是吗? 这应该是这样的。

[如果你想看OP代码片段的代码片段和细节的原始答案的剩余部分,请参阅修订历史logging]

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

  [childViewController willMoveToParentViewController:nil]; [childViewController view] removeFromSuperview]; [childViewController removeFromParentViewController]; 

是删除和添加它的方式是

  [parentViewController addChildViewController:childViewController]; [parentViewController.view addSubview:childViewController.view]; [childViewController didMoveToParentViewController:parentViewController]; 

经过几个小时,试图找出发生了什么,我终于发现是什么导致我的孩子视图控制器正确释放。

每个视图控制器都在每个视图控制器中声明了以下通知,以便它们可以响应各种事件。

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

原因是某些原因使我的视图控制器无法正确释放。 我猜测,这添加到NSNotificationCenters观察员列表视图控制器,并没有被删除时,我做了以下的一行。

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

所以要解决我的问题,我只是改变了通知注册如下。

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateEvent:) name:UPDATE_EVENT object:nil]; 

我不知道为什么我注册通知的方式不允许我的视图控制器正确释放,但这似乎已经修复了它。 如果任何人有任何见解,为什么会发生这个问题,请让我知道。

谢谢!