【问题标题】:Memory not released in ios view hierarchyios视图层次结构中未释放内存
【发布时间】:2012-01-05 18:43:12
【问题描述】:

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

我的问题是,在 ViewController 之间切换时内存没有被释放。

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

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

viewDidUnload 永远不会被调用。有谁有一个很好的例子如何构建一个干净的视图层次结构?

【问题讨论】:

  • viewDidUnload 仅在内存不足的情况下被调用

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


【解决方案1】:

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

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

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 属性,因为指向已释放内存的指针存在危险。

【讨论】:

  • 非常感谢,消除了我对如何创建视图控制器以便尽快发布它们的疑虑!
【解决方案2】:

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

尝试在模拟器中触发内存警告,看看是否会导致 viewDidUnload 方法触发。如果是这样,那么一切都很好。如果不是,您可能会以某种方式过度保留您的视图,也许是通过将它们分配给其他强保留属性。

视图保留策略有一些例外情况,例如 UINavigationController 会释放其视图控制器堆栈中的视图(如果它们不是最前端的),但它通过简单地将其子控制器的视图设置为 nil 来做到这一点。被另一个控制器的视图覆盖。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-03
    • 2010-10-19
    相关资源
    最近更新 更多