什么时候应该在-(void)viewDidUnload中释放对象,而不是在-dealloc中释放对象?


Answers:


51

除了已经指出的内容之外,我还想详细说明后面的逻辑-viewDidUnload

实现它的最重要原因之一是UIViewController子类通常还包含对视图层次结构中各个子视图的拥有引用。例如IBOutlets,从笔尖加载时可以设置这些属性,也可以通过编程方式在内部设置这些属性-loadView

子视图的额外所有权是UIViewController指,即使将其视图从视图层次结构中删除并释放以节省内存(视图也通过该视图释放了子视图),由于它们UIViewController本身仍包含自己的未完成的视图,因此实际上不会释放它们也保留对这些对象的引用。释放UIViewController这些对象的额外所有权可确保将它们重新分配以释放内存。

通常,从Nib或通过的实现重新创建并释放您在此处释放的对象,并在UIViewController视图打开时重新设置这些对象。re-loaded-loadView

还要注意,该UIViewController view属性是nil在调用此方法时出现的。


1
您应该阅读developer.apple.com/library/ios/#featuredarticles/…以了解视图/视图控制器的生命周期
Paul Solt 2010年

21

文档所述

当视图控制器需要释放其视图以及与该视图关联的任何对象以释放内存时,在低内存条件下将调用它。

在相同的情况下dealloc不会叫。此方法仅在OS3及更高版本中可用。在iPhone OS 2.x中处理相同的情况真是太痛苦了!

2015年7月更新:应该注意,viewDidUnloadiOS 6 中已弃用该方法,因为“视图不再在低内存条件下清除,因此从不调用此方法。” 因此,现代建议是不要担心它和使用它dealloc


6
同样在文档中:“您应该仅对以后可以轻松重新创建的对象执行此操作,无论是在viewDidLoad方法中还是在应用程序的其他部分。都不应使用此方法释放用户数据或任何其他无法轻松地重新创建”。我自己也是个问题,谢谢!
leolobato

如果该视图当前可见,该怎么办?因为内存不足警告而将其删除会不会很糟糕?;),那么该应用将只是空白为空。由于内存不足,我无法释放视图。如果看不到视图,则始终释放整个控制器。我有一个根视图控制器,它保持完整并管理其子视图控制器的所有加载/卸载...
感谢

不,如果只是将一个视图交换为另一个视图,则不会使用此方法。考虑一下使用UINavigationController拥有视图“堆栈”的情况。只有一个视图可见,并且,如果有内存警告,则可以释放所有不可见的视图。
斯蒂芬·达林顿

谢谢,您如何控制未在当前可见视图上调用viewDidUnload?
arielcamus 2010年

1
仅在不可见的视图上,不会在当前可见的视图上调用viewDidUnload。
progrmr

9

这是因为通常您将设置为@propertyas "(nonatomic, retain)"和as这样为您创建的setter会释放当前对象,然后保留参数,即

self.property = nil;

...采取以下措施:

[property release];
property = [nil retain];

因此,您要用一块石头杀死两只鸟:内存管理(释放现有对象)并将指针分配给nil(因为将任何消息发送到nil指针都会返回nil)。

希望能有所帮助。


8

请记住,这viewDidUnload是视图控制器中的方法,而不是视图中的方法。当视图卸载时,将调用该视图的 dealloc方法,但是直到稍后才可以调用该视图控制器的 dealloc方法。

如果收到内存不足警告,并且视图未显示(例如,在使用UIImagePickerController允许用户拍照时的任何时候都会发生这种情况),则视图将被卸载,并且此后需要重新加载。


这就说得通了。如果我总是放弃整个视图控制器,会发生什么?那是我真正要做的。在这种情况下,我不必处理-viewDidUnload,对吗?我从来没有遇到过只放下视图的情况,因为如果总不可见,我总是放下整个控制器。
感谢

好吧,请记住,在您的视图正在显示的情况下,但是您具有全屏视图(例如其顶部的ImagePicker),即使您不打算使用它,也可能会卸载视图。
David Maymudes 09年

6

结论:

视图控制器具有视图属性。通常,笔尖或一段代码将其他视图添加到该视图。这通常发生在-viewDidLoad方法内部,如下所示:

- (void)viewDidLoad {
    [super viewDidLoad];
    [self createManyViewsAndAddThemToSelfDotView];
}

另外,nib文件可以创建一个按钮并将其附加到视图控制器的视图。

在iPhone OS 2.2上,从系统调用-didReceiveMemoryWarning时,必须释放一些内容以释放内存。如果可以的话,您可以释放整个视图控制器的视图。或者只是其中消耗大量内存的内容。

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
    // Release anything that's not essential, such as cached data
}

现在,在新的OS 3.0中,有一个-viewDidUnload方法,当由于内存不足而将视图卸载后,将从系统中调用该方法(请纠正我:何时确切调用此方法?)

-viewDidUnload用于释放视图控制器本身和视图都拥有的所有对象。原因:如果视图控制器持有对视图子视图(即按钮)的引用,则将不会释放所引用的子视图,因为它们的保留计数> =1。在-viewDidUnload中释放它们之后,可以释放它们。从记忆里。


1
鉴于reber确实卸载了self.button = nil ;,而不是[button release];。
mk12

6

Apple不赞成使用viewWillUnload,现在您应该使用didReceiveMemoryWarning或dealloc释放objetcs。

在iOS 6中,现已弃用UIViewController的viewWillUnload和viewDidUnload方法。如果使用这些方法来释放数据,请改用didReceiveMemoryWarning方法。您也可以使用此方法释放对视图控制器视图的引用(如果未使用它)。在执行此操作之前,您需要测试视图不在窗口中。


5

如果视图控制器从导航控制器堆栈中弹出,并且未在其他任何位置保留,它将被释放,并调用dealloc而不是viewDidUnload。您应该在dealloc中释放在loadView中创建的视图,但是没有必要将变量设置为nil,因为在调用dealloc之后不久,变量将不再存在。


3

您可以释放所保留的任何子视图,例如保留在loadView方法中的UIImageView,或者更好的是该UIImageView上的图像。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.