我正在阅读关于内存管理的苹果文档,并遇到了一些我不明白的内容.基本上,我不明白为什么不需要通过"getter"方法保留实例变量.我写了这个小程序,看看会发生什么.我以为会有崩溃,但我显然错过了一些东西.
// main.m // Test // #import#import "Test.h" int main(int argc, char *argv[]) { NSAutoreleasePool *p = [[NSAutoreleasePool alloc] init]; //Initialize the test object Test *t = [[Test alloc] init]; //Set the value to 5 [t setMyNum:[NSNumber numberWithInt:5]]; //Save a temp number that points to the original number NSNumber *tempNum = [t myNum]; //release old number and retain new [t setMyNum:[NSNumber numberWithInt:7]]; //Shouldn't this crash because tempNum is pointing to a deallocated NSNumber??? NSLog(@"the number is %@",tempNum); [p drain]; return 0; }
tempNum不指向解除分配的对象吗?
所有帮助表示赞赏.
编辑这是getter和setter方法中的代码
#import "Test.h" @implementation Test - (void)setMyNum:(NSNumber *)newNum { [newNum retain]; [myNum release]; myNum = newNum; } -(NSNumber *)myNum { return myNum; } @end
正如您所看到的,我正在调用旧对象上的release.
编辑有人建议,我认为这是正确的,因为tempNum仍然存在的原因是因为它尚未从池中自动释放.但即使在NSLog消息之前将[pool drain]移动到右边,也没有崩溃??? 奇怪的.
由于您没有显式释放任何对象,因此在允许自动释放池耗尽之前不会释放任何内容.尝试[p drain]
在最后一次NSLog
通话前插入.它应该崩溃NSLog调用.
此外,如果您没有在setMyNum:方法中保留NSNumber,您会发现如果[p drain]
在分配tempNum之前添加它将会崩溃.
为了澄清原始问题,调用getter方法不会(也不应该)必然意味着调用者想要获取所有权(即保留)变量.如果是这种情况,此代码将泄漏:
NSLog("Number is %@", [t myNum]);
此外,NSNumber似乎有一个优化,对于小数字,它们缓存NSNumber对象,保留额外的副本,并返回该版本.因此对于小常量,[NSNumber numberWithInt: N]
将返回具有2个引用计数的对象(可通过[theNumber retainCount]
).要明确地看到会发生什么,在程序中使用一个更大的常量,NSNumber将保留一个引用计数为1的"新鲜"对象(也将自动释放).