NSString 保留计数

NSString Retain Count

下面提到的代码片段中 NSString 的保留计数是多少?

self.a = @"abcd"; // self.a is a NSString with (nonatomic, Strong) Attributes

NSLog(@"Retain Count of A == %d",(int)[self.a retainCount]);

self.b = self.a;// self.b is a NSString with (nonatomic, Strong) Attributes

NSLog(@"Retain Count of A == %d",(int)[self.a retainCount]);
NSLog(@"Retain Count of B == %d",(int)[self.b retainCount]);

[self.a release];

NSLog(@"Retain Count of A == %d",(int)[self.a retainCount]);
NSLog(@"Retain Count of B == %d",(int)[self.b retainCount]);


//Similarly whats the retain count if:
self.b = [self.a retain];

@"abcd" 是字符串文字。它存储为常量。如果您要记录 [@"abcd" class],那么您会得到 __NSCFConstantString(尽管这是经验观察;不保证 class 名称)。 retainrelease 等是对常量字符串的空操作,因为它本质上与应用程序具有相同的生命周期。实际上,正如 vikingosegundo 所说,你会得到 NSUIntegerMax.

您正在使用属性,因此实际发生的情况取决于您的 属性 类型。

对于 self.b = self.a 你期望的是:

  • getterself.areturns[[string retain] autorelease],因此保留计数在当前自动释放池的生命周期内递增;
  • setter self.b = 保留字符串,因此保留计数再次递增,在 self 的字符串所有权的生命周期内。

如果您在自动释放池的生命周期内检查,那么两次增量,一次长期增量。

手动调用 retainrelease 完全符合您的想法。

在 ARC 下,您不需要手动调用任何这些东西,包括 retainCount 并且各种保留和释放可能会被优化掉。一个著名的案例是自动释放池中随后保留的某些东西可以从池中删除。因此 self.b = self.a 可能会以保留计数仅增加 1 而字符串不在自动释放池中结束,如果优化器喜欢的话。

使用手动引用计数的规则相当简单:

  • 如果您有一个拥有的引用——一个由新的、分配的、保留的或复制的返回的引用——然后释放或自动释放引用;
  • 如果你有一个非拥有的引用——即任何其他类型,最常见的是来自香草getter——那么不要发布引用。但不一定期望它在当前自动释放池的生命周期之后有效。

return [[a retain] autorelease] 模式来自观察 self 的生命周期可能比池短。