Objective-C通过引用计数来管理内存,每个对象都有一个计数器,其值表明还有多少个其他对象想令此对象继续存活。
NSObject协议中定义了下列方法,用于查询对象当前的保留计数:
- (NSUInteger)retainCount
ARC中已经废弃此方法了,非ARC环境仍然可用,但是不应该用。
原因一:它所返回的保留计数只是某个给定时间点上的值。并未考虑到系统会稍后把自动释放池清空,因而不会将后续的释放操作从返回值里减去,所以此值就未必能真实反应实际的保留计数了。
while([object reatinCount]){
[object release];
}
这种写法的错误在于,它没有考虑后续的自动释放操作,假如对象在自动释放池中,稍后系统清空池子还要再释放对象一次,引起程序崩溃。
原因二:reatinCount可能永远不返回0,因为有时系统会优化对象的释放行为,在保留计数还是1的时候就把它回收了。
reatinCount返回的保留计数具体值也不一定有用:
NSString *string = @"Some string";
NSLog(@"string retainCount = %lu",[string retainCount]);
NSNumber *numberI = @1;
NSLog(@"numberI retainCount = %lu",[numberI retainCount]);
NSNumber *numberF = @3.14f;
NSLog(@"numberF retainCount = %lu",[numberF retainCount]);
运行结果:
2018-10-14 15:17:07.681609+0800 Demo[940:32158] string retainCount = 18446744073709551615
2018-10-14 15:17:09.143573+0800 Demo[940:32158] numberI retainCount = 9223372036854775807
2018-10-14 15:17:10.599497+0800 Demo[940:32158] numberF retainCount = 1
第一个对象的保留计数是2的64次方减1,第二个是2的63次方减一。由于二者都是单例对象,所以其保留计数都很大。系统会尽可能把NSString实现成单例对象,NSNumber也类似,它使用了一种叫做标签指针的概念来标注特定类型的数值,将有关信息都存放在指针值里。由于浮点数没有此优化,所以保留计数为1。
对于单例对象来说,保留计数永远不会变,保留及释放都是空操作。
由于对象可能出在自动释放池中,其保留计数未必如想象般精确,而且其他程序库也可能自行保留或释放对象,这都会扰乱计数的具体取值。所以任何情况下都不要使用retainCount。
网友评论