我有一个复制NSString的类,打印它的保留计数和地址。
@interface TestStringPointer : NSObject
@property (copy) NSString *stringTest;
- (void)printPointer;
@end
@implementation TestStringPointer
- (void)printPointer {
NSLog(@"PrintPointer:%p\n RetainCount:%lu", _stringTest, [_stringTest retainCount]);
}
@end
在我的main函数中,我对String的指针进行了一些调查并遇到了一个问题。
int main(int argc, const char * argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
TestStringPointer *test = [[TestStringPointer alloc] init];
NSString *myString = [NSString stringWithUTF8String:"Hello World"];
NSLog(@"MyString: %p \n RetainCount:%lu", myString, [myString retainCount]);
[test setStringTest:myString];
[test printPointer];
[myString release];
[pool drain];
while (1) {
[test printPointer];
}
return 0;
}
当我调试应用程序时,它通过while循环第三次崩溃(循环次数变化)。我知道副本不会发生导致字符串不可变。
在主要版本发布后,我希望它能回到1。
1)如果一个对象没有自动释放,它是否仍然影响自动释放池?
2)没有最大保留计数会阻止对象在池中耗尽,还是会将其标记为删除?
3)副本是否应该在某个时刻介入并在删除之前实际制作副本?
StringPointerTest [2253:303] MyString:0x100100f60 RetainCount:1
StringPointerTest [2253:303] PrintPointer:0x100100f60 RetainCount:2
StringPointerTest [2253:303] PrintPointer:0x100100f60 RetainCount:1152921504606846975
StringPointerTest [2253:303] PrintPointer:0x100100f60 RetainCount:1152921504606846975
如果我修改main并删除池
int main(int argc, const char * argv[])
{
TestStringPointer *test = [[TestStringPointer alloc] init];
NSString *myString = [NSString stringWithUTF8String:"Hello World"];
NSLog(@"MyString: %p \n RetainCount:%lu", myString, [myString retainCount]);
[test setStringTest:myString];
[test printPointer];
[myString release];
while (1) {
[test printPointer];
}
return 0;
}
一切都是对的...永远......
StringPointerTest [423:303] MyString:0x10010a670 RetainCount:1
StringPointerTest [423:303] PrintPointer:0x10010a670 RetainCount:2
StringPointerTest [423:303] PrintPointer:0x10010a670 RetainCount:1
...
答案 0 :(得分:0)
错误在于你释放myString
。这是错误的,因为stringWithUTF8String
返回一个自动释放的字符串(请记住,每个方法都有自动释放的版本:静态方法,非自动释放的版本:init或initWithSomething :)。因此,当自动释放池耗尽时,myString
保留计数变为零并且对象被解除分配(可能稍后,您不确切知道何时,它在第3次循环迭代时崩溃的事实是偶然的)。
因此,您可以致电alloc
+ initWithUTF8String:
而不是stringWithUTF8String:
来解决问题。你看到一个令人难以置信的高保留计数的事实只是因为内存已被释放并且可能再次被写入,在对象被真正解除分配之前,它只是一个陷阱,你不再拥有该对象。