第29条:理解引用计数
2018-09-30 本文已影响6人
MrSYLong
Objective-C语言使用引用计数来管理内存,每个对象都有一个可以递增或递减的计数器。如果想使某个对象存活,那就递增其引用计数,用完后递减其计数,计数变为0,就销毁对象。
引用计数工作原理
“引用计数”也可以叫做“保留计数”。
NSObject协议下声明了三个方法用于操作引用计数:
- retain:递增引用计数
- release:递减引用计数
- autorelease:待稍后清理“自动释放池”时,再递减引用计数
不要使用retainCount查看引用计数。
对象创建出来时,其引用计数至少为1.若想令其继续存活,则调用retain方法。要是不再使用此对象,不想令其继续存活,那就调用release或autorelease方法。最终引用计数为0时,对象就回收了,其占用内存被系统标为“可重用”。所有指向此对象的引用都变为无效。
应用程序在其生命周期中会创建很多对象,这些对象相互联系,构成一张“对象图”。其中会有一个“根对象”,在Mac OS X应用程序中是NSApplication对象,在iOS应用程序中是UIApplication对象,都是应用程序启动时创建的单例。
为避免使用无效对象,一般调用完release之后都会清空指针。
// MRC下:
NSMutableArray *array = [[NSMutableArray alloc] init];
NSNumber *number = [[NSNumber alloc] initWithInt:1314];
[array addObject:number];
[number release];
number = nil;
属性存取方法中的内存管理
一个对象可以保留其他对象,一般通过访问“属性”来实现。访问属性时,会用到相关实例变量的获取方法及设置方法,若属性为“strong关系”,则设置的属性值会保留。
// MRC下:
- (void)setFoo:(id)foo {
[foo retain];
[_foo release];
_foo = foo;
}
注意:顺序很重要,先保留新值并释放旧值,然后更新实例变量,令其指向新值。
自动释放池
调用release会立刻递减对象的引用计数(而且还可能令系统回收此对象)。
调用autorelease会稍后递减引用计数,通常是下一次“事件循环”时递减。
自动释放池的特性,在方法中返回对象时尤其应该被使用。
// MRC下:
- (NSString *)stringValue {
NSString *str = [[NSString alloc] initWithFormat:@"I am this %@",self];
return str;
}
为令返回的str对象被调用者使用,并且为保证str对象调用alloc后引用计数加1有与之对应的是否操作,这里应该调用autorelease
- (NSString *)stringValue {
NSString *str = [[NSString alloc] initWithFormat:@"I am this %@",self];
return [str autorelease];
}
autorelease方法能延长对象生命周期,使其在跨越方法调用边界后依然可以存活一段时间。
一般会在当前线程的下一次事件循环调用对象的释放操作。
保留环
保留环问题通常采用“弱引用”来解决,也可以从外界命令循环中的某个对象不再保留另一个对象。