一.set方法内存管理
当一个对象拥有另一个对象的属性时,需要在set方法对当前所拥有的对象做retain操作,因为你的属性是指向了另一个对象,需要让另一个对象知道有单元在使用我。
但是这样写的话不够完善,会出现新的问题。如果对象属性之前已经指向了某一个对象了,此时再传进来一个新的对象,属性指针就指向了新的对象,然后retain了新的对象,但是旧的对象此时并没有人工release过,需要release一下。还有一个问题就是在release旧对象,retain新对象之前要做一个判断,判断一下此时拥有的对象和以前拥有的对象是否都是指向同一个对象,如果是的话就不需要做任何release和retain操作。
下面是演示代码,创建一个Person类和Car类,Person类属性有Car这个类。
1 #import <Foundation/Foundation.h> 2 #import "Car.h" 3 4 @interface Person : NSObject 5 { 6 Car *_car; 7 int _age; 8 } 9 10 - (void)setAge:(int)age; 11 - (int)age; 12 13 - (void)setCar:(Car *)car; 14 - (Car *)car; 15 16 @end
1 #import "Person.h" 2 3 @implementation Person 4 - (void)setCar:(Car *)car 5 { 6 if (car != _car) 7 { 8 // 对当前正在使用的车(旧车)做一次release 9 [_car release]; 10 11 // 对新车做一次retain操作 12 _car = [car retain]; 13 } 14 } 15 - (Car *)car 16 { 17 return _car; 18 } 19 20 - (void)setAge:(int)age 21 { // 基本数据类型不需要管理内存 22 _age = age; 23 } 24 - (int)age 25 { 26 return _age; 27 } 28 29 - (void)dealloc 30 { 31 // 当人不在了,代表不用车了 32 // 对车做一次release操作 33 [_car release]; 34 35 NSLog(@"%d岁的Person对象被回收了", _age); 36 37 [super dealloc]; 38 } 39 40 @end
1 #import <Foundation/Foundation.h> 2 3 @interface Car : NSObject 4 { 5 int _speed; 6 } 7 8 - (void)setSpeed:(int)speed; 9 - (int)speed; 10 @end
1 #import "Car.h" 2 3 @implementation Car 4 - (void)setSpeed:(int)speed 5 { 6 _speed = speed; 7 } 8 - (int)speed 9 { 10 return _speed; 11 } 12 13 14 - (void)dealloc 15 { 16 NSLog(@"速度为%d的Car对象被回收了", _speed); 24 25 [super dealloc]; 26 } 27 28 @end
总结:
1> 内存管理代码规范:
1.只要调用了alloc,必须有release(autorelease)
2.对象不是通过alloc产生的,就不需要release
2> set方法的代码规范
1. 基本数据类型:直接复制
- (void)setAge:(int)age
{
_age = age;
}
2. OC对象类型
- (void)setCar:(Car *)car
{
// 先判断是不是新传进来对象
if ( car != _car )
{
// 对旧对象做一次release
[_car release];
// 对新对象做一次retain
_car = [car retain];
}
}
3> dealloc方法的代码规范
1. 一定要[super dealloc],而且放到最后面
2. 对self(当前)所拥有的其他对象做一次release
二.property参数
上述代码显然比较麻烦的,每次都要按照格式写set方法。property参数可以帮助我们改进代码。
1> set方法内存管理相关的参数
1.retain : release旧值,retain新值(适用于OC对象类型),潜复制,只复制指针。
2. assign : 直接赋值(默认,适用于非OC对象类型)
3.copy : release旧值,copy新值,深复制,复制内容和指针。
2> 是否要生成set方法
1.readwrite : 同时生成setter和getter的声明、实现(默认)
2. readonly : 只会生成getter的声明、实现
3> 多线程管理
1.nonatomic : 性能高 (一般就用这个)
2.atomic : 性能低(默认)
4> setter和getter方法的名称
1.setter : 决定了set方法的名称,一定要有个冒号 :
2.getter : 决定了get方法的名称(一般用在BOOL类型)
有了property参数的帮助,我们的代码就省了很多。我们一旦用了retain和assign参数,那么系统会自动把我们的代码转化为set方法和get方法的规范代码,无需我们手动编写。上述代码加入property参数后变成了如下精简的代码。
1 #import <Foundation/Foundation.h> 2 #import "Car.h" 3 4 @interface Person : NSObject 5 6 @property (nonatomic,assign) int age; 7 @property (nonatomic,retain) Car *car; 8 9 @end
1 #import "Person.h" 2 3 @implementation Person 4 5 - (void)dealloc 6 { 7 [_car release]; 8 NSLog(@"%d岁的Person对象被回收了", _age); 9 [super dealloc]; 10 } 11 12 @end
1 #import <Foundation/Foundation.h> 2 3 @interface Car : NSObject 4 5 @property (nonatomic,assign) int speed; 6 7 @end
1 #import "Car.h" 2 3 @implementation Car 4 5 - (void)dealloc 6 { 7 NSLog(@"速度为%d的Car对象被回收了", _speed); 8 [super dealloc]; 9 } 10 11 @end