原文见http://www.cnblogs.com/wwwkhd/archive/2011/03/14/1983192.html和http://zhgw01.blog.163.com/blog/static/104148122011844621458/
由init、loadView、viewDidLoad、viewDidUnload、dealloc的关系说起
init方法
在init方法中实例化必要的对象(遵从LazyLoad思想)
init方法中初始化ViewController本身
loadView方法
当view需要被展示而它却是nil时,viewController会调用该方法。不要直接调用该方法。
如果手工维护views,必须重载重写该方法
如果使用IB维护views,必须不能重载重写该方法
loadView和IB构建view
你在控制器中实现了loadView方法,那么你可能会在应用运行的某个时候被内存管理控制调用。 如果设备内存不足的时候, view 控制器会收到didReceiveMemoryWarning的消息。 默认的实现是检查当前控制器的view是否在使用。 如果它的view不在当前正在使用的view hierarchy里面,且你的控制器实现了loadView方法,那么这个view将被release, loadView方法将被再次调用来创建一个新的view。
viewDidLoad方法
viewDidLoad 此方法只有当view从nib文件初始化的时候才被调用。
重载重写该方法以进一步定制view
在iPhone OS 3.0及之后的版本中,还应该重载重写viewDidUnload来释放对view的任何索引
viewDidLoad后调用数据Model
viewDidUnload方法
当系统内存吃紧的时候会调用该方法(注:viewController没有被dealloc)
内存吃紧时,在iPhone OS 3.0之前didReceiveMemoryWarning是释放无用内存的唯一方式,但是OS 3.0及以后viewDidUnload方法是更好的方式
在该方法中将所有IBOutlet(无论是property还是实例变量)置为nil(系统release view时已经将其release掉了)
在该方法中释放其他与view有关的对象、其他在运行时创建(但非系统必须)的对象、在viewDidLoad中被创建的对象、缓存数据等 release对象后,将对象置为nil(IBOutlet只需要将其置为nil,系统release view时已经将其release掉了)
一般认为viewDidUnload是viewDidLoad的镜像,因为当view被重新请求时,viewDidLoad还会重新被执行
viewDidUnload中被release的对象必须是很容易被重新创建的对象(比如在viewDidLoad或其他方法中创建的对象),不要release用户数据或其他很难被重新创建的对象
dealloc方法
viewDidUnload和dealloc方法没有关联,dealloc还是继续做它该做的事情
看到以下的代码
- (void)viewDidUnload {
self.detailViewController = nil;
self.languageNames = nil;
self.languageCodes = nil;
}
- (void)dealloc {
[detailViewController release];
[languageNames release];
[languageCodes release];
[super dealloc];
}
如果是先调用viewDidUnload后再调用dealloc, 那么languageNames都已经是nil了,再掉release有什么意义呢?
原因似乎是, 对一个viewcontroller来说,它的数据的初始化在init中,而它管理的view采用了lazy load的方式,也就是有需要的时候才会载入, 所以跟view相关的数据可以在viewDidLoad(也就是在view被载入的时候)进行初始化。当内存紧张的时候, ios会销毁点一些view, 通过调用viewDidUnload (里面一般也只是把跟view相关的数据设为nil), 但这个时候viewcontroller本身还在, 所以它的dealloc不会被调用,除非是到了viewcontroller也被销毁的时候.
再见,viewDidUnload方法
转自@唐巧_boy 的博客。
我在去年的一篇文章《iOS5中UIViewController的新方法》中介绍了iOS5引入的关于ViewController的新方法。但是现在如果运行该文章中的Sample代码的话,你会发现Log中不会再出现viewDidUnload方法被调用的记录。这是因为在iOS6中,viewDidUnload回调方法被Deprecated掉了。查看苹果的文档,可以看到如下的说明。
那么,原本在viewDidUnload中的代码应该怎么处理?在iOS6中,又应该怎么处理内存警告?带着这些问题,我查找了一些资料,在此分享给大家。
分析
在iOS4和iOS5系统中,当内存不足,应用收到Memory warning时,系统会自动调用当前没在界面上的ViewController的viewDidUnload方法。通常情况下,这些未显示在界面上的ViewController是UINavigationController Push栈中未在栈顶的ViewController,以及UITabBarViewController中未显示的子ViewController。这些View Controller都会在Memory Warning事件发生时,被系统自动调用viewDidUnload方法。
在iOS6中,由于viewDidUnload事件在iOS6下任何情况都不会被触发,所以苹果在文档中建议,应该将回收内存的相关操作移到另一个回调函数:didReceiveMemoryWarning 中。但是如果你仅仅是把以前写到viewDidUnload函数中的代码移动到didReceiveMemoryWarning函数中,那么你就错了。以下是一个 错误的示例代码 :
1.- (void)didReceiveMemoryWarning {
2. [super didReceiveMemoryWarning];
3. if([self isViewLoaded] && ![[self view] window]) {
4. [self setView:nil];
5. }
6.}
这篇文章解释了iOS6不推荐你将view置为nil的原因(链接打开需要FQ), 翻译过来如下:
1.UIView有一个CALayer的成员变量,CALayer是具体用于将自己画到屏幕上的。如下图所示:
2.CALayer是一个bitmap图象的容器类,当UIView调用自身的drawRect时,CALayer才会创建这个bitmap图象类。
3.具体占内存的其实是一个bitmap图象类,CALayer只占48bytes, UIView只占96bytes。而一个iPad的全屏UIView的bitmap类会占到12M的大小!
4.在iOS6时,当系统发出MemoryWarning时,系统会自动回收bitmap类。但是不回收UIView和CALayer类。这样即回收了大部分内存,又能在需要bitmap类时,通过调用UIView的drawRect: 方法重建。
内存优化
另外文章中还提到苹果的操作系统对此做的一个内存优化技巧,解释如下:
当一段内存被分配时,它会被标记成“In use“, 以防止被重复使用。当内存被释放时,这段内存会被标记成”Not in use”,这样,在有新的内存申请时,这块内存就可能被分配给其它变量。
CALayer包括的具体的bitmap内容的私有成员变量类型为CABackingStore, 当收到MemroyWarning时, CABackingStore类型的内存区会被标记成volatile类型(这里的volatile和 C以及Java语言的volatile不是一个意思),volatile表示,这块内存可能被再次被原变量重用。
这样,有了上面的优化后,当收到Memoy Warning时,虽然所有的CALayer所包含的bitmap内存都被标记成volatile了,但是只要这块内存没有再次被复用,那么当需要重建bitmap内存时,它就可以直接被复用,而避免了再次调用 UIView的 drawRect: 方法。
总结
所以,简单来说,对于iOS6,你不需要做任何以前viewDidUnload的事情,更不需要把以前viewDidUnload的代码移动到 didReceiveMemoryWarning方法中。
引用WWDC 2012 中的一段话来给viewDidUnload说再见:
The method viewWillUnload and viewDidUnload. We’re not going to call them anymore. I mean, there’s kind of a cost-benifit equation and analysis that we went through. In the early days, there was a real performance need for us to ensure that on memory warnings we unloaded views. There was all kinds of graphics and backing stores and so forth that would also get unloaded. We now unload those independently of the view, so it isn’t that big of a deal for us for those to be unloaded, and there were so many bugs where there would be pointers into。
参考链接
iOS7的viewDidUnload没了,那要取消之前的网络请求之类的,要写在哪?
如果放在viewWillDisappear那里,在得到http返回前如果先segue到别的地方,又经常会出现无法显示联网内容。不知大家明不明白我在说什么。。。
v i e w D i d U n l o a d 和 d e a l l o c 的 区 别 ,
牛b极了,透彻极了。虽然v i e w D i d U n l o a d 已经被苹果弃用,但是此文可以有助于理解苹果内存管理机制。同时启发对didReceiveMemoryWarning的理解。
对于iphone开发人员来说,内存管理是极为重要的技巧,哪怕程序的功能再强大,设计再漂亮,如果内存控制不好,也难逃程序莫名退出的噩运,这与网页开发是完全不同的。 内存控制里面有很多门道,在这里分析一下 viewDidUnload 和 dealloc 的区别,关于这两者的区别的文章很多,但是大都是摘抄和翻译官方文档,有的也只是简单的说两句,并没有详细说出两者具体的区别。
在了解两者之间的区别,首先要知道 view 的生命周期,google 里面有很多文章,可以先去搜一下,这里就不详解了。
顾名思义 viewDidUnload 就是当 view 被卸载以后执行的语句,它与 viewDidLoad 是相互呼应的。大家都知道官方的解释是执行类似 self.myOutlet = nil;
中国返利网 http://www.chinafanli.com/ 汇丰农牧http://www.szhfnm.com/ 艺时尚 http://www.artzhu.com/
的命令,但是为什么这么干,什么时候调用这个方法呢?
这个方法是不能手动调用的,它实际上是当应用程序接收到手机内存警告的时候自动调用的方法,目的就是清空内存除当前 viewController 以外所有已经加载过的 viewController 里面的暂时不再使用的一些控件或数据,以避免应用程序应消耗内存过多被强制关闭。记住,是除当前正在展示的 view 所属 viewController 以外所有已经在内存里面的 viewController 执行 viewDidUnload 方法,而不是当前 viewController 执行
viewDidUnload,当然,这些 viewController 不会被 dealloc。所以在 viewDidUnload 里面一般都是释放 IBOutlet 变量和在 viewDidLoad、viewWillAppear、viewDidAppear 等方法能够重建的数据。而由其他页面传递过来的数据或者无法经过 viewDidLoad、viewWillAppear、viewDidAppear 等方法重建的数据则不能释放,举例子说如果在 navigationController 由上一个页面传递过来的一张图片,在 viewDidUnload 里被释放的话,则当 view 再次加载的时候就无法恢复了。
那为什么要写成 self.myOutlet = nil; ,实际上这个语法是执行了 property 里的setter 方法,而不是一个简单的变量赋值,它干了两件事:1、老数据 release 掉,2、新数据(nil)retain(当 property 设置为 retain 的情况下),当然对 nil retain 是无意义的。如果写成 myOutlet = nil,那就是简单的把 myOutlet 指向 nil,这样内存就泄漏了,因为老数据没有 release。而如果仅仅写成 [myOutlet release] 也会有问题,因为当 view 被 dealloc 的时候会 再次 release,程序就出错了,而对 nil release 是没有问题的。
dealloc 是当前 viewController 被释放的时候,清空所有当前 viewController 里面的实体和数据来释放内存,该方法也是自动调用的,无需手动执行。举例说明当 modalView 被 dismissModalViewControllerAnimated 或者 navigationController 回到上一页的时候,这个方法就会被自动调用。因为这个页面已经不再使用了,所以可以把所有实体和数据都释放(release)掉。
其实两者最大的区别就是: viewDidUnload 是内存除当前以外所有 viewController 同时执行,而 dealloc 只是当前 viewController 执行。这个是网上的材料没有说明的
iOS Objective-C dealloc方法释放的是什么?
一个对象当我不使用它时,可以release或autorelease,为什么还要在dealloc方法中在释放一次?
回答:如一个对象 A,A 有一个属性 p ,p 也是一个对象,A 还有很多方法。
如果 A 的很多方法都用到了 p 属性,如果在其中一个方法中释放了 p 属性,其它方法使用 p 属性时 p 属性已经不存在了,程序就出错。
那要什么时候释放 p 属性呢?
dealloc 方法会在对象销毁时程序自动调用。
也就是说 当 A 对象被销毁时程序就会自动调用 A 对象的 dealloc 方法,这时在 dealloc 方法中就可以释放 p 属性了。
dealloc 方法中主要用于释放对象的属性。