首页 > 代码库 > iOS开发入门 ? OC语言·笔记五
iOS开发入门 ? OC语言·笔记五
MRC — 手动管理内存
1.1 内存引用平衡原则
1) 如果使用alloc,new开头,或者是copy(复制一个对象)来创建一个对象,意味着你拥有这个对象的所有权。这个对象的引用计数器初始值为1(也有可能>1)。
2) 如果你拥有这个对象的所有权,在不使用此对象时,就有责任向对象发送release消息。(谁创建了对象,谁就有责任release这个对象)
3) 如果并不拥有一个对象的所有权,而想要使用这个对象,为了防止你在使用此对象期间,对象被别人释放掉,需要向对象发送retain消息,以保持对象。此时可以认为,你也拥有了这个对象所有权。
4) 当你使用完retain过的对象后,有责任release一下这个对象。
(谁retain了一个对象,谁就有责任release这个对象)
配对出现:(+1、-1 ==>平衡)
我们创建的对象不用了,就release;我们retain的对象不用了,就release。
内存管理的原则就是有加就有减。也就是说, 一次alloc(new)对应一次release, 一次retain对应一次release
1.2 自动释放池(autoreleasepool)
通过自动释放池来管理对象,只需要一个自动释放池,可以管理很多对象,当自动释放池结束的时候,会自动向池中的每个对象都发送release消息。
1) 如果一个对象创建后,不能马上释放它,但又不得不尽到释放对象的责任,此时可以将对象放入自动释放池,延迟对象的释放时机。比如绝大部分工厂方法都是如此。工厂方法中的对象是方法中创建的,按理来说应该由工厂方法内部释放,但工厂方法的功能决定了这个对象不能马上释放,此时应该将对象放入自动释放池。
2) 当自动释放池结束时,会向池中的所有对象发送release消息,如果此时,池中的对象的引用计数器是1,那么,对象会被释放掉。
3) 如何开始和结束一个自动释放池呢?
//自动释放池,用于回收对象的存储空间。 @autoreleasepool{ //开始(创建一个自动释放池) …… …… } //结束(自动释放池销毁了, 给自动释放池中所有的对象发送一条release消息) |
还有一种性能低下,被淘汰的自动释放池创建方式(了解)
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];//开始一个自动释放池 …… …… [pool drain];//结束一个自动释放池 |
4) 无论一个对象是否在自动释放池,只要这个对象是由别人创建的,你要使用此对象,就得retain,用完此对象,就得release,即使对象在自动释放池,也依然如此。
5) 实际开发中,合理使用自动释放池来避免内存使用出现峰值。
如果App出现的内存使用的峰值,此时才考虑是否是由于大量使用工厂方法造成的,是否需要使用自动释放池解决问题。要合理使用自动释放池,大量使用会消耗系统资源。
6) autorelease方法:在自动释放池中使用,目的是将对象添加到自动释放池中。自动释放池销毁时会对池中对象作release操作。(延迟release)
@autoreleasepool { Person *p = [[[Person alloc] init] autorelease];
} |
- autorelease方法与release方法的区别:这两个方法都能把对象的引用计数器减1。
- release是一个精确的减1,对对象的操作只能在release之前进行,如果是在之后,就会出现野指针错误;
- autorelease是一个不精确的引用计数器减1,当给对象发送autorelease消息时,对象就会被放到自动释放池中,自动释放池销毁时会给池中的所有对象发送release消息,使得所有对象的计数器减1,所以本质上autorelease还是会调用release。
- 常见错误:
// 销毁自动释放池的时候 要对person再执行release操作的话 会报野指针错误 @autoreleasepool { Person *person = [[[Person alloc] init] autorelease]; [person release]; } |
// 对象执行两次autorelease意味着自动释放池销毁的时候 对象会执行两次release操作 会报野指针错误 @autoreleasepool { Person *person = [[[[Person alloc] init] autorelease] autorelease]; } |
1.3 setter方法的内存管理(应用场景:两个类是聚合关系)
当一个方法传入一个对象后,如果需要将这个对象用实例变量等手段保存起来持续使用时,需要做以下事:
1) 先将此对象的引用计数器加1(retain)
2) 再将原来实例变量指向的对象的引用计数器减1(release)
3) 最后将传入的对象地址保存到实例变量中
4) 被retain的对象通常需要在dealloc方法中release.
只要一个对象想使用房间,就需要对这个房间的引用计数器+1
只要一个对象不想使用房间,就需要对这个房间的引用技术器-1
经常会被问到的问题:
1) 前面3个顺序可否颠倒?
能不能先release原来的对象,再赋值,最后retain新对象? 一般可以,但不建议
2) dealloc方法中,可不可以使用self.属性 = nil;的方式释放属性所指向的对象? ok的
可以的,self.属性 相当于调用上面的setter方法(该方法中有向对象发release)
Demo:setter方法的内存管理
iOS开发入门 ? OC语言·笔记五