1、引用计数
在iOS中,使用引用计数来管理OC对象的内存一个新创建的OC对象引用计数默认是1,当引用计数减为0,OC对象就会销毁,释放其占用的内存空间。
// 创建出来引用计数是1
Person *person = [[Person alloc] init];
NSLog(@"%zd",person.retainCount);
// release后引用计数变为0,内存被释放
[person release];
NSLog(@"end");
~: 1
~: -[Person dealloc]
~: end
*如果对象在不使用的时候没有调用release,就会造成内存泄漏
2、set方法
给Person类添加一个成员变量_dog
@interface Person : NSObject {
Dog *_dog;
}
最简单的set方法如下面的代码所示,直接给_dog赋值
- (void)setDog:(Dog *)dog {
_dog = dog;
}
但是如果外部创建dog后再release,dog就会被销毁,person就不能再继续使用dog,这样person和dog就没有持有关系了,需要在set方法里给dog调用retain方法,并在person销毁时,销毁内部成员变量_dog,保证person和成员变量_dog的生命周期保持一致:
- (void)setDog:(Dog *)dog {
_dog = [dog retain];
}
- (void)dealloc {
// 销毁成员变量
[_dog release];
_dog = nil;
// 父类的dealloc放在后面执行
[super dealloc];
}
这样还有一个问题就是当person重新设置一个新的dog时,之前设置的dog引用计数没有减1,会造成内存泄漏,所以需要在设置新dog时,对旧的dog执行release操作:
- (void)setDog:(Dog *)dog {
[_dog release]; // 旧dog 引用计数-1
_dog = [dog retain]; // 新dog 引用计数+1
}
- (void)dealloc {
// 销毁成员变量
[_dog release];
_dog = nil;
// 父类的dealloc放在后面执行
[super dealloc];
}
如果person重复调用setDog并且传入的是同一个dog对象,就会对dog进行重复释放,所以在release前需要判断一下是否是同一个dog,set方法最终方案如下:
- (void)setDog:(Dog *)dog {
if (_dog != dog) { // 避免重复释放
[_dog release];
_dog = [dog retain];
}
}
- (void)dealloc {
// 销毁成员变量
[_dog release];
_dog = nil;
// 父类的dealloc放在后面执行
[super dealloc];
}
*基本数据类型,不是oc对象没有自动引用计数,set方法直接赋值即可。
3、属性
给Person添加age、dog、car三个属性
@interface Person : NSObject
@property (nonatomic, assign) int age;
@property (nonatomic, retain) Dog* dog;
@property (nonatomic, retain) Car* car;
@end
编译器会自动添加_开头的成员变量,并且添加set和get,在set方法内部实现引用计数相关操作。
在Person对象释放时,需要手动释放属性:
- (void)dealloc {
self.dog = nil;
self.car = nil;
[super dealloc];
}
*在编译器自动添加成员变量前、需要使用@synthesize关键字,它可以设置属性的成员变量名称,并且会自动生成成员变量的setter、getter实现,例如: @synthesize age = _age;