1、引用计数
在iOS中,使用引用计数来管理OC对象的内存一个新创建的OC对象引用计数默认是1,当引用计数减为0,OC对象就会销毁,释放其占用的内存空间。
// 创建出来引用计数是1Person *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;
