解释两次发生的alloc / init

时间:2011-10-25 16:12:45

标签: iphone objective-c ios memory-management

我意识到这个问题可能听起来很愚蠢,但只是忍受我。我构建了一个应用程序来帮助新开发人员围绕iPhone保留内存(还没有ARC)。它简单明了,有4个按钮,初始化,访问,保留和释放。非常自我解释。我正在显示我的字符串对象的保留计数,它是我们戳戳和刺激的目标。 (请不要讲授[myVar retainCount]的使用,我已经知道了)

这些东西永远不会成为真正的应用程序,只是玩弄它的乐趣,并希望帮助别人了解记忆的运作方式。我保留和释放所有工作都很棒。我的问题是,如果我调用myString = [[NSMutableString alloc] init],为什么我的保留计数会回落到1;再次。我可以将保留计数提高到40,但在调用alloc / init后我会回到零。我没有泄漏任何地方,只是好奇myString如果/再次调用alloc / init时会发生什么。

3 个答案:

答案 0 :(得分:28)

  

我的问题是,如果我打电话,为什么我的保留计数会回落到1   再次myString = [[NSMutableString alloc] init];

因为您未能理解Objective-C的一个非常基本的概念; myString不是NSMutableString的实例,而是对实例的引用。如果你是:

myString = [[NSMutableString alloc] init];
myString = [[NSMutableString alloc] init];

你现在有两个NSMutableString实例,一个泄露。

如果你:

myString = [[NSMutableString alloc] init];
otherString = myString;

您现在拥有一个带有两个引用的NSMutableString实例。

在所有三个分配中,NSMutableString实例将具有+1保留计数,因此,您必须使用单个release进行平衡,否则您将泄漏。

将保留计数视为绝对计数是疯狂的途径。或者,充其量,绝对保留计数的有用范围非常有限,因此了解它并不适用于真实的iOS编程。


这有点重复:

对象的retainCount是一件棘手的事。

如果您继续沿着这条路走下去,您应该了解以下细节:

  • retainCount永远不会返回0
  • 消息传递悬挂指针不能保证崩溃
  • 由于实施细节而导致通过任何系统API传递对象后,无法知道保留计数
  • 由于实现细节,任何系统类的任何子类都可能具有未知的保留计数
  • 保留计数从不反映对象是否已自动释放
  • autoreleases实际上是特定于线程的,而保留计数是线程全局的
  • 有些类在某些时候用单例实现(NSString,NSNumber的某些值)
  • 实施细节从平台变为平台,发布到发布
  • 尝试调动retain / release / autorelease将无效,因为某些类实际上并未使用这些方法来维护保留计数(实现细节,每个平台的更改/释放等。)

如果您要教导保留/释放,您应该将保留计数视为三角形,并完全关注“如果您增加RC,则必须减少它”。

答案 1 :(得分:11)

当你致电myString = [[NSMutableString alloc] init];时,你不是“再次调用alloc / init”。您没有在同一个实例上调用方法。您正在分配和初始化一个新实例,这是一个与之前完全不同的对象。

如果您使用的变量具有您保留的对象,那么是的,您正在泄漏它。

答案 2 :(得分:2)

试试这个。

NSString *myString = [[NSMutableString alloc] init];
NSLog(@"%d", [myString retainCount]); // "1"
for (int i = 1; i < 40; i++)
    [myString retain];
NSLog(@"%d", [myString retainCount]); // "40"

NSString *backup = myString;
myString = [[NSMutableString alloc] init];
NSLog(@"%d", [myString retainCount]); // "1"
NSLog(@"%d", [backup retainCount]); // "40"

您会看到,您有一个具有新保留计数的其他对象。您的原始对象仍然存在,但仍具有相同的保留计数。赋值更改变量引用的对象。变量没有保留计数,而对象则没有。

myString = someOtherString;
NSLog(@"%d", [myString retainCount]); // who knows?

保留属性:

self.iString = backup;
NSLog(@"%d", [self.iString retainCount]); // "41" - 1 more because property retained
NSString *newString = [[NSMutableString alloc] init];
NSLog(@"%d", [newString retainCount]); // "1"
self.iString = newString;
// 1 for alloc 1 for retain (in real code you should release newString next)
NSLog(@"%d", [self.iString retainCount]); // "2"
NSLog(@"%d", [backup retainCount]); // "40" - self.iString released it