------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
一、局部变量和指向对象的指针存放在栈中,它们是局部变量。程序会自动回收它们。对象存放在堆中,需要手动进行管理。
二、对象的计数器。
- 对象的结构,每个对象都有自己的引用计数器,表示对象被引用的次数。
- 每个对象都会特地分配4个字节的空间来存放引用计数器。
- 当计数器为0时,对象将会被销毁,内存被回收。
- 当使用alloc、new和copy创建新对象的时候,对象的引用计数器为1。
- 当给对象发送retain消息的时候(调用对象retain方法),对象计数器 + 1;
- 当给对象发送release消息的时候,对象的计数器 - 1。
- 给对象发送一条retainCount方法,获取当前的引用计数器数值。
对象的销毁
- 当一个对象的引用计数器为0时,他将被销毁,所占用的内存被系统回收。
- 当一个对象销毁时,系统会自动向对象发送一条dealloc消息。
- 一般会重写dealloc方法,在这里释放相关资源,dealloc就像对象的遗言。
- 一旦重写了dealloc方法,就必须调用[super dealloc],并且放在最后面调用。
- 千万不要直接调用dealloc方法
retain方法返回的是对象本身。
[p retain] == p;
三、野指针和空指针
僵尸对象:引用计数器被减为0的对象就是僵尸对象,当某个对象引用计数器为0的时候,指向它的指针还指向它。但是它已经不可用了。所以指向它的指针,变为了野指针。
野指针:指向僵尸对象(不可用的内存)的指针,就叫野指针。
操作野指针是一个危险的行为。
为了防止野指针:
- 在对象计数器减为0之后,清空指针p = nil;给空指针发送消息不会报错。
- OC里面没有空指针错误。JAVA里面有空指针错误。
多个对象内存管理原则:
- 你像要使用某个对象,你就给他+1
- 你不想要某个对象,就给他 - 1
- 有加就有减
- 如果对象不是通过alloc产生的,就不许产生对应的release。比如NSString
<span style="font-family:SimHei;font-size:18px;">- (void)setCar:(Car *)car
{
if (_car != car) {
[_car release];
_car = [car retain];
}
}
</span>
先判断旧的成员变量和新的是否一样,如果一样,不做任何操作,如果不一样,则把旧的release掉,新的retain,然后在赋值。五、@property内存管理
之前的 @propertyBook *book;它自动生成的set方法是没有内存管理功能的。
当在@property(retain) Book *book; 加上(retain)就会在set方法中生成内存管理代码。
retain代表了生成了set方法里面release旧值,retain新值。
最后别忘了在dealloc中release对象成员变量。
注意,基本数据类型不能添加(retain)
1、@property内存管理相关的参数(三选一,只能写一个)
- retain : release旧值,retain新值(适用于OC对象)
- assign: 直接赋值(默认的,基本数据类型用这种,写不写都行。)
- copy : release旧值, copy新值
2、是否要生成set方法(二选一,只能写一个)
- readonly : 只读,不生成set方法,只生成get方法的声明和实现。
- readwrite : 可读可写(默认)
3、多线程管理
- nonatomic : 告诉系统,生成set方法的时候不要生成多线程代码(性能高)(建议必写)
- atomic : (性能低)(默认)
4、setter和getter方法的名称
- getter = 新的方法名(一般用来修改BOOL)
- setter = 新的方法名:(注意后面的冒号)
- 这两个不冲突,可以写在一起。
六、循环引用。
1、@class 类名; 仅仅是告诉编译器 card是一个类。
两个相互引用的对象,不能都用 #import 互相引用.h文件,这里用class。
用了@class后,.m文件要#import 要包含的文件的.h文件。
规范
- 在头文件中使用@class
- 在.m文件中用#import包含.h文件。
2、循环引用的内存管理
两个对象循环引用两端都用retain会导致对象都无法被销毁。
解决方案:两端循环引用的解决方案:
- 一端用retain
- 一端用assign(用assign别忘了不要再dealloc方法中release)