我意识到这个问题可能听起来很愚蠢,但只是忍受我。我构建了一个应用程序来帮助新开发人员围绕iPhone保留内存(还没有ARC)。它简单明了,有4个按钮,初始化,访问,保留和释放。非常自我解释。我正在显示我的字符串对象的保留计数,它是我们戳戳和刺激的目标。 (请不要讲授[myVar retainCount]的使用,我已经知道了)
这些东西永远不会成为真正的应用程序,只是玩弄它的乐趣,并希望帮助别人了解记忆的运作方式。我保留和释放所有工作都很棒。我的问题是,如果我调用myString = [[NSMutableString alloc] init],为什么我的保留计数会回落到1;再次。我可以将保留计数提高到40,但在调用alloc / init后我会回到零。我没有泄漏任何地方,只是好奇myString如果/再次调用alloc / init时会发生什么。
答案 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 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