1、什么是内存管理
内存管理是关于如何管理对象生命周期的编程原则
OC的内存管理只针对于对象,基本数据类型不需要管理内存
当以一个对象没有再被使用时,应该从内存中释放掉
所以的对象都有一个计数器,叫做引用计数(retainCount),表示该对象当前被多少“人”在使用。
当引用计数为0时,系统会销魂该对象
2、alloc、retain、release
alloc用来创建对象,对象创建完成后,计数为1,只被调用一次。
retain使引用计数+1,可被调用多次。
relese使引用计数-1,可被调用多次。
当引用计算为0,该对象会被销魂,在销魂之前会调用dealloc方法
Student *student=[[Student alloc] init];
NSLog(@"alloc后的retainCount=%ld",student.retainCount);
[student retain];
NSLog(@"第一次retain后的retainCount=%ld",student.retainCount);
[student retain];
NSLog(@"第二次retain后的retainCount=%ld",student.retainCount);
[student release];
NSLog(@"第一次release后的retainCount=%ld",student.retainCount);
[student release];
NSLog(@"第二次release后的retainCount=%ld",student.retainCount);
//第三release后retainCount=0,对象被销魂
[student release];
为了知道对象是否被销魂了,我们应该重写dealloc方法,注意要调用[super dealloc];
@implementation Student
- (void)dealloc
{
[super dealloc];
NSLog(@"销魂了");
}
@end
打印的结果
如果提示不能alloc、retain、release,说明项目的Automatic Refrence Counting设置成了YES,修改方法
3、对象所以权
当一个所有者(本身也是对象)做了alloc、retain、[mutable]copy这些动作,它就拥有了一个对象的所有权
使用release、autorelease释放对象所有权
4、黄金法则
如何一个对象是用来alloc,[mutable]copy,retain,那必须使用对应的release或autorelease释放,保证内存平衡。
5、如何持有一个对象
6、数组的内存管理
set方法持有对象所以权
-(void)setBook:(Book *)book
{
//如果是同一个对象就不必再设置了
if (_book!=book) {
[_book release];//释放掉之前的所有权
_book=[book retain];//retain获得新对象的所有权
}
}
自定义初始化方法,持有对象所有权
- (instancetype)initWithBook:(Book *)book
{
if (self=[super init]) {
_book=[book retain];
}
return self;
}
dealloc方法
当对象被销毁时,对调用dealloc方法,应该在dealloc方法中释放其他对象的所有权
- (void)dealloc
{
[super dealloc];
[_book release];
NSLog(@"销毁了");
}
NSMutableArray *books=[NSMutableArray array];
Book *book1=[[Book alloc] init];
Book *book2=[[Book alloc] init];
[books addObject:book1];//book1会被数组retain,计数+1
[books addObject:book2];//book2会被数组retain,计数+1
//黄金法则,alloc对应release,成对出现
[book1 release];
[book2 release];
数组销毁时或者调用removeAllObjects方法时,会对数组内存每一个元素发送release消息
[books removeAllObjects];
移除对于下标的元素的同时,会对它发送release消息
[books removeObjectAtIndex:0];
7、自动释放池
自动释放池是OC的一种内存自动管理机制
当自动释放池销毁时,它会对池内的所有对象调用一次release方法
当我们向一个对象发送autorelease消息时,这个对象就被放入到自动释放池中
@autoreleasepool {
Book *book1=[[Book alloc] init];
//加入到自动释放池
[book1 autorelease];
}
在autoreleasepool以外调用autorelease,则该对象就不归这个自动释放池管
自动释放池可以嵌套使用
autorelease会将对象放到离它最近的自动释放池
int main(int argc, const char * argv[])
{
//自动释放池1
@autoreleasepool {Book *book1=[[Book alloc] init];
Book *book2=[[Book alloc] init];
//自动释放池2
@autoreleasepool {
[book1 autorelease];//book1归自动释放池2管,
}//程序走过这个括号后,自动释放池2就会被销魂,book1会被release
//book2归自动释放池1管
[book2 autorelease];
}//程序走过这个括号后,自动释放池1就会被销魂,book2会被release
return 0;
}
典型例子(错误),以下代码会有内存泄露