1.引用计数工作原理
●Retain 递增保留计数
●Release 递减保留计数
●Autorelease 待稍后清理“自动释放池”时,再递减保留计数。
*OC使用引用计数来管理内存,也就是说,每个对象都有个可以递增或者递减的计数器。如果想使某个对象继续存活,那就递增其引用计数,用完了之后就递减其计数。计数变为0,就表示没人关注此对象了,于是,就可以把它销毁。
*在iOS程序中,如果按引用树回溯,那么最终会发现一个根对象,为UIApplication对象。
2.属性存取方法中的内存管理
访问属性时,会用到相关实例变量的获取方法及设置方法,若属性为“strong关系”,则设置的属性值会保留。例如:
- (void)setFoo:(id)foo {
[foo retain];
[_foo release];
_foo = foo;
}
此方法将保留新值并释放旧值,然后更新实例变量,令其指向新值。顺序很重要,假如还未保留新值就把旧值给释放了,而且两个值又指向同一对象,那么先执行的release操作就可能导致系统将此对象永久回收。而后续的retain操作则无法令这个已经彻底回收的对象复生,于是实例变量就成了悬挂指针。
3.自动释放池
在OC的引用计数架构中,自动释放池是一项重要特性。调用release会立刻递减对象的保留计数,而且还有可能令系统回收此对象,然而有时候可以不调用它,改为调用autorelease,此方法会在稍后递减计数,通常是在下一次“事件循环”时递减,也可能更早些。
例如:
- (NSString *)stringValue {
NSString *str = [[NSString alloc] initWithFormat:@"str"];
return str;
}
因为调用alloc此时对象保留计数会增加1,如果在方法内部调用release会导致还没等方法返回,系统就将该对象进行回收。这里应该调用autorelease,它会在稍后释放对象,从而给调用者留下了足够长的时间,使其可以在需要时先保留返回值。实际上,释放操作会在清空最外层的自动释放池时执行,就是当前线程的下一次事件循环。
- (NSString *)stringValue {
NSString *str = [[NSString alloc] initWithFormat:@"str"];
return [str autorelease];
}
修改之后,stringValue方法把NSString对象返回给调用者,此对象必然存活。
但是,假如要持有此对象的话,比如将其设置给实例变量,那就需要保留,并与稍后释放:
_instanceVariable = [[self stringValue] retain];
//...do...
[_instanceVariable release];
由此可见,autorelease能延长对象生命周期,使其在跨越方法调用边界后依然可以存活一段时间。
4.保留环
互相强引用导致循环引用,通常采用“弱引用”来解决此问题,或时从外界命令循环中的某个对象不在保留另外一个对象。