<span style="font-family:Microsoft YaHei;font-size:14px;">@implementation Peson
-(void)dealloc
{
NSLog(@"Person对象被回收");
[super dealloc];
}</span>
4、僵尸对象、野指针
1> 僵尸对象:当对象的引用计数器变为0时,对象就会被回收,意味着当前存储空间 不能用,此时这个对象就变成了“僵尸对象”。
2> 野指针:指向僵尸对象(不可以内存)的指针成为野指针。
注意:给野指针发送消息会野指针错误,报错提示:EXC_BAD_ACCESS
3> 空指针:没有指向任何对象的指针(nil、NULL、0),给空指针发送消息不会报错。
5、多对象内存管理
特点:1> 只要有人在用某个对象,那么这个对象就不会被回收;
2> 只要你想用这个对象,就让对象的计数器加1(让对象做一次retain操作);
3> 当你不再使用这个对象时,就让对象的计数器减1(让对象做一次release操作)。
总之:谁创建,谁release,谁retain,谁release。
6、
set方法的内存管理
1> 只要调用了alloc,必须有release(或autorelease),如果对象不是通过alloc创建的,则不需要release。
2> setf方法的代码规范:
基本数据类型:
-(viod)setAge:(int)age
{
_age = age;
}
oc对象类型:
-(void)setWithCar:(Car *)car
{
if(car != _car) //判断传进来的是不是新对象
{
[_car release]; //获取新对象时,需要对旧对象做一次release
_car = [car retain];//需要对新对象做一次retain。
}
}
3> dealloc方法的代码规范
1)一定要[super dealloc],并且放在最后面;
2)对self(当前对象)所拥有的其他对象做一次release。
-(viod)dealloc
{
[_car release]; //当人会回收了,代表车也不用了,所以需要对车做一次release。
NSLog(@"Person对象被回收!");
[super dealloc];
}
7、property的内存管理
1> 默认情况下,在声明中@property Book *book;会自动生成setter和getter方法,但都只是赋值操作,没有retain操作。
但若写成@property (retain)Book *book;在生成的set方法里面,会自动release旧值,retain新值。
2>property的参数:
set方法内存管理相关的参数:
1) retain :release旧值,retain新值(适用于OC类型的对象);
2) assign:直接赋值(默认),适用于非OC对象类型;
3) copy:release旧值,copy新值。
多线程管理
1) nonatomic:性能高(一般就用这个)
2)atomic:性能低。
8、循环引用
@class
1>对于循环依赖关系,比如A类import B类,B类同时也import A类
这种情况下代码会报错,此时如果将其中一个import改成@class,就不会报错了。
2> @class的作用:声明一个类,仅仅告诉编译器,某个名称是一个类。eg:@class Person,
需注意:
1)@class仅仅声明这个类,不会将此类的方法和成员变量导入,当真正用到这个类的时候,在.m文件中#import这个类。
2)可以循环声明,如A声明B,B声明A。
3> @class与#import的区别
1)#import方式会包含被引用类的所有信息,包括被引用类的变量和方法;
@class方式只是告诉编译器在A.h文件中的B类只是一个类,具体这个类有什么信息,这里不需要知道,等文件中真正要用到的时候,才会去查看B类中的信息。
2)如果有上百个头文件都#import了同一个文件,或者这些文件依次被#improt,那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,降低效率。(A->B B->C C->D……,一旦A变动,则后面都需要重新编译)。
3)
在.m实现文件中,如果需要引用到被引用类的实体变量或者方法时,还需要使用#import方式引入被引用类。
循环retain
概念:比如A对象retain了B对象,B对象retain了A对象,这样会导致A对象和B对象永远无法释放。
解决方案:当两端相互引用时,应该一端用retain、一端用assign。
eg:
//car
@property (nonatomic,retain)Person *person;
//Person
@property (nonatomic,assign)Car*car
9、autorelease
1> 作用:1)给某个对象发送一条autorelease消息时,就会将这个对象加到一个自动释放池中,
当自动释放池销毁时,会给池子里面的所有对象发送一条release消息。
2)调用autorelease方法时并不会改变对象的计数器,并且会返回对象本身。
需注意:当自动释放池被销毁时,对象不一定被销毁,只是做一次release操作。
eg:
@autoreleasepool
{ //代表开始创建了自动释放池
Book *book = [[[Book alloc] init] autorelease];//必须存在自动释放池,才能写autorelease。
}//代表销毁自动释放池
需注意:1>autorelease方法返回对象本身;
2>autorelease 会将对象放到一个自动释放池中;
3> 当自动释放池被销毁时,会对池子里面的所有对象做一次release操作
4> 调用完autorelease方法后,对象的引用计数器值不变。
2>autorelease的好处:不用再关心对象的释放时间,即不用关心什么时候调用autorelease。
autorelease的缺点:不能精确的控制内存销毁的时间。所以尽量用release,便于精确控制。
3> 使用注意:1)占用内存较大的对象不要随便用autorelease。
2)占用内存较小的对象(比如int float double等)使用autorelease,没太大影响。
4> @autoreleasepool
{
Person *p = [[[Person alloc]init]autorelease]auturelease;
}
注意:以上代码会发生野指针错误,写两次autorelease意味着当池子销毁时,会对对象做两次release操作。所以不能写两次autorelease。