内存未在ios视图层次结构中发布

时间:2012-01-05 18:43:12

标签: ios cocoa-touch uiviewcontroller automatic-ref-counting

我有一个使用ARC的iOS应用程序。我不使用InterfaceBuilder,所有UI都是手动生成的。在那个应用程序中,我有几个带有SubViewControllers的UIViewControllers。那些ViewControllers是从一个菜单(-ViewController)绑定在一起的,它将它们推送到堆栈上。

我的问题是,在ViewControllers之间切换时,内存不会被释放。

像这样保持对SubViewControllers的引用是错误的吗?

@property (nonatomic, strong) UIViewController subViewController1; 
@property (nonatomic, strong) UIViewController subViewController2;

viewDidUnload永远不会被调用。有没有人如何建立一个干净的视图层次结构?

2 个答案:

答案 0 :(得分:5)

通过将在堆栈上推送的视图控制器分配给强实例变量/属性,当从堆栈弹出时,它们将不会被释放。即使在推出的视图控制器从堆栈中弹出之后,强大的属性仍然存在,因此它们永远不会到达可以解除分配的状态。

通常,当将下一级向下视图控制器推送到导航堆栈时,我会执行以下操作:

SLSMoleculeSearchViewController *searchViewController = [[SLSMoleculeSearchViewController alloc] initWithStyle:UITableViewStylePlain];
[self.navigationController pushViewController:searchViewController animated:YES];

在ARC下,将分配新的视图控制器,并在创建时保留。当推入导航堆栈时,导航控制器将保留一次。由于此新视图控制器在被推送后未被引用,并且未分配给强属性或实例变量,因此ARC将在第二行之后将其释放。

请记住,它仍然被导航控制器保留,所以它仍然存在于内存中。但是,一旦导航控制器将其弹出堆栈,该视图控制器将被释放。由于此时没有任何内容,它将按预期释放。

如果由于某种原因需要在更高级别的视图控制器中维护对此子视图控制器的引用,则可以使用weak属性或__weak实例变量。这将不会保留在视图控制器上,并且一旦取消分配控制器,它将变为nil。

weak引用仅支持针对iOS 5.0的应用程序,因此您无法为需要在iOS 4.0上运行的任何内容执行此操作。在这种情况下,由于存在指向解除分配内存的指针的危险,因此我不建议使用4.0兼容的unsafe_unretained属性。

答案 1 :(得分:0)

这很可能与ARC无关。 viewDidUnload仅在视图属性被释放/设置为nil时在视图控制器上调用,这通常仅在应用程序收到内存警告时才会发生。

尝试在模拟器中触发内存警告,看看是否会导致viewDidUnload方法触发。如果它确实那么一切都很好。如果没有,您可能会以某种方式过度保留您的观点,可能是将它们分配给其他强烈保留的属性。

视图保留策略有例外,例如UINavigationController在视图控制器堆栈中释放视图(如果它们不在最前面),但它只是通过简单地将其子控制器的视图设置为nil来实现。被另一个控制者的观点所覆盖。

如果您希望在不在屏幕上时释放视图,请在viewDidDisappear:方法中将控制器的视图属性设置为nil,或者在视图不在屏幕上时停止保留视图控制器并仅创建新控制器每次需要显示实例时(这样,控制器和视图都将在不使用时释放)。