【问题标题】:Releasing IBOutlets in UIViewController’s viewDidUnload?在 UIViewController 的 viewDidUnload 中释放 IBOutlets?
【发布时间】:2011-03-12 05:23:28
【问题描述】:

对于基于 Nib 的 UIViewControllers 中究竟发生了什么,我有点困惑。在生成UIViewController 子类时,模板在viewDidUnload 方法中包含一个非常具体的注释:

// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;

这适用于哪些子视图?

  • 我在viewDidLoad中初始化的那些? (我会说是的)
  • 我在initWithNibName中初始化的那些? (我会说不)
  • 引用 Nib 中对象的 IBOutlets?

如果我像这样使用视图控制器:

MyViewController *controller = [[MyViewController alloc] initWithNibName:@"MyViewController" bundle:nil];
[self.navigationController pushViewController:controller animated:YES];
[controller release];

在这种情况下,我认为持有对子视图的引用的实例变量是否在viewDidUnloaddealloc 中释放并不重要,因为一旦视图控制器从堆栈中弹出,dealloc 就会被调用所以我不妨像苹果说的那样在viewDidUnload而不是dealloc上释放实例变量。

但假设我使用MyViewController 作为实例变量,可能会被推送多次:

if(self.myViewController == nil) {
    self.myViewController = [[MyViewController alloc] initWithNibName:@"MyViewController" bundle:nil];
}
//Change some state which should be reflected in the view
self.myViewController.someProperty = someValue;
[self.navigationController pushViewController:self.myViewController animated:YES];

如果我在 viewDidUnload 中发布 IBOutlet,MyViewController 会发生什么?我可以指望在下一个viewDidLoad 上有一个新的引用吗?

换句话说:在viewDidUnload 之后视图本身会发生什么?如果再次推动控制器,它是否会从 Nib 释放并重新加载?或者视图是否保留在内存中?如果是这样,网点会在viewDidLoad 之前重新设置吗?

如果视图保留在内存中并且在viewDidLoad 之前重新设置了插座,或者每次按下控制器时都重新加载,我想在viewDidUnload 中释放插座是正确的(即使在第一种情况没关系)。但除此之外(特别是如果视图保留在内存中并且未重新设置插座),对于我提出的用例来说,释放 viewDidUnload 中的子视图是错误的,我正确吗?

【问题讨论】:

  • 更新:请注意,viewDidUnload 将在 iOS 6 中被弃用,因为显然它让很多开发人员(不仅仅是我)感到困惑,而且他们经常以某种方式错误地使用它,当开发人员没有考虑到内存警告时,这将导致他们的应用程序崩溃/行为不端......

标签: objective-c iphone uiviewcontroller nib ios


【解决方案1】:

来自UIViewController documentation,内存管理部分:

当发生内存不足警告时,UIViewController 类如果知道以后可以重新加载或重新创建视图,则会清除其视图。如果发生这种情况,它还会调用 viewDidUnload 方法,让您的代码有机会放弃与视图层次结构关联的任何对象的所有权,包括使用 nib 文件加载的对象、在您的 viewDidLoad 方法中创建的对象,以及对象在运行时延迟创建并添加到视图层次结构中。通常,如果您的视图控制器包含插座(包含IBOutlet 关键字的属性或原始变量),您应该使用viewDidUnload 方法放弃这些插座或您不再需要的任何其他视图相关数据的所有权。

因此,您不仅可以在viewDidUnload 中发布您的网点,而且这是首选和推荐的方式。

是的,当viewDidLoad 被调用时,您可以指望让您的出口指向有效对象。再次来自 UIViewController 文档,viewDidLoad:

在视图控制器将其关联的视图加载到内存后调用此方法。

【讨论】:

  • 只是为了确保:如果在 viewDidLoad: 中添加其他视图,则必须在 viewDidUnload: 中删除并释放它们,因为很可能 viewDidLoad: 将在稍后第二次被调用并且我会留下多个附加子视图的副本吗?
  • 首先,你真的应该通过属性来做所有的内存管理,而不是直接访问ivars。要回答您的问题,即使您在 dealloc 中使用属性和释放(因此不会导致内存泄漏),仍然没有必要保留它们,因为它们将在 viewDidLoad 中重新创建。
  • 按照您的指导,我应该使所有保留对象的属性,从而放松私有变量的概念,对吗?
  • @afEkenholm:私有和属性不一定是互斥的,可以有私有属性。
猜你喜欢
  • 2011-01-22
  • 2011-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-13
  • 2011-04-29
  • 2010-11-20
  • 1970-01-01
相关资源
最近更新 更多