前言
例如,有如下代码: Person对象的定义如下: @interface Person : NSObject { Car *_car; } – (void)setCar:(Car *)car; – (Car *)car; – (void)drive; – (void)dealloc; @end @implementation Person – (void)setCar:(Car *)car { [_car release]; _car = [car retain]; } – (Car *)car { return _car; } – (void)drive { NSLog(@"走,去拉萨。。。); [_car run]; } – (void)dealloc { [_car release]; NSLog(@“人挂了。。。”); [super dealloc]; } @end
Car类的定义如下: @interface Car : NSObject { int _speed; } – (void)setSpeed:(int)speed; – (int)speed; – (void)run; – (void)dealloc; @end @implementation Car – (void)setSpeed:(int)speed { _speed = speed; } – (int)speed { return _speed; } – (void)run { NSLog(@“时速为%d的车,在行驶”,_speed); } – (void)dealloc { NSLog(@“车挂了。。。”); [super dealloc]; } @end
main.h文件中: #import <Foundtaion/Foundtaion.h> #import “Person.h” int main() { Person *p1 = [[Person alloc] init]; Car *bmw = [Car new] bmw.speed = 100; p1.car = bmw; [p1 drive]; [bmw release]; bmw.speed = 200; p1.car = bmw; [p1 release];
return 0; }
这时候,会报这句话发生僵尸对象错误: – (void)setCar:(Car *)car { [_car release]; _car = [car retain];//这句话,会报僵尸对象错误
一、出现僵尸对象错误的原因
1)一开始,有一个Person对象p1,然后,有一个Car对象bmw,把bmw的speed属性,赋值为100,然后,把bmw作为p1对象的car属性,赋值给p1对象的car属性,这时候,怎么赋值的: a 先把_car指向的对象release,这时候,_car为nil,release方法没有反应 b 再把bmw对象retain,再赋值给p1对象的_car属性。这时候,bmw对象的引用计数器的值为2 2)bmw对象,调用release方法,这时候,bmw对象的引用计数器的值为1 3)bmw对象的speed属性变为200 4)bmw对象,作为p1对象的_car属性,赋值给p1对象的_car属性,这时候,怎么赋值的: a _car 指向的对象先release,_car现在指向bmw对象,bmw对象的引用计数器的值是1,release之后,bmw对象的引用计数器变为0 b bmw对象再retain,这时候,retain的了吗,retain不了,因为bmw对象已经被销毁了。 5)出现僵尸对象错误的原因: 在于, 新旧对象是同一个对象
二、解决方案
1.当发现新旧对象是同一个对象的时候,setter方法什么都不用做,只有当新旧对象不是同一个对象的时候,才release旧的,retain新的
– (void)setCar:(Car *) { if(_car != car) { [_car release]; _car = [car retain]; } }
(_car != car)这个条件如果成立,说明什么问题啊,是不新旧对象不是同一个对象,不是同一个对象,我才去干嘛呢,才去release旧的,retain新的。 如果是同一个对象呢,什么都不做。
2.最终完美的setter方法的写法:
– (void)setCar:(Car *)car { if(_car != car) { [_car release]; _car = [car retain]; } }
dealloc方法最终完美版怎么写:
– (void)dealloc { [_car release]; [super dealloc]; }
特别注意,我们内存管理的范围,是OC对象,所以,只有属性的类型是OC对象,这个属性的setter方法,才要像上面那样写,如果属性不是OC对象类型的,setter方法直接赋值就可以了,例如Person 对象的age属性
特别注意,NSString *类型的属性,需要像上面那样写setter方法,例如Person 对象的name属性,因为NSString 是一个OC类
– (void) setName:(NSString *)name { if(_name != name) { [_name release]; _name = [ name retain]; } } – (void)dealloc { [_name release]; [super dealloc]; }
|