我正在阅读memory management的苹果文档,并遇到了一些我不明白的内容。基本上,我不明白为什么不需要通过“getter”方法保留实例变量。我写了这个小程序,看看会发生什么。我以为会有崩溃,但我显然错过了什么。
// main.m
// Test
//
#import <Foundation/Foundation.h>
#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
正如你所看到的,我正在调用旧对象的释放。
编辑有人提出,我认为这是正确的,因为tempNum仍然存在的原因是因为它尚未从池中自动释放。但即使在NSLog消息之前将[pool drain]移动到右边,也没有崩溃???怪异。
答案 0 :(得分:5)
由于您没有显式释放任何对象,因此在允许自动释放池耗尽之前不会释放任何内容。尝试在最后[p drain]
次来电之前插入NSLog
。它应该使NSLog调用崩溃。
此外,如果您没有在setMyNum:方法中保留NSNumber,您会发现如果在分配tempNum之前添加[p drain]
,它将会崩溃。
为了澄清原始问题,调用getter方法不会(也不应该)必然意味着调用者想要获取所有权(即保留)变量。如果是这种情况,这段代码就会泄漏:
NSLog("Number is %@", [t myNum]);
此外,NSNumber似乎有一个优化,对于小数字,它们缓存NSNumber对象,保留额外的副本,并返回该版本。因此,对于小常量,[NSNumber numberWithInt: N]
将返回具有2个引用计数的对象(可通过[theNumber retainCount]
获得)。要明确地看到会发生什么,在程序中使用一个更大的常量,NSNumber将保留一个引用计数为1的“新鲜”对象(也将自动释放)。
答案 1 :(得分:1)
#import "Test.h"
@implementation Test
- (void)setMyNum:(NSNumber *)newNum
{
[newNum retain];
[myNum release];
myNum = newNum;
}
-(NSNumber *)myNum
{
return myNum;
}
@end
这里的setter方法[myNum release]
释放了mynum,但后来我们又给了一些newnum的新值,因此从getter方法中,临时数字得到的数字直到{{ {1}}所以不会有任何崩溃。
答案 2 :(得分:0)
#import "Test.h"
@implementation Test
(void)setMyNum:(NSNumber *)newNum
{
[newNum retain];
[myNum release];
myNum = newNum;
}
(NSNumber *)myNum
{
return myNum;
}
@end
这是setter方法[myNum release];
,它释放了myNum
,但是我们再次给出一些新值newNum
,因此从getter方法中临时数得到数字在[p drain];
之前尚未解除分配,因此不会发生任何崩溃。即使以下代码不会崩溃,因为有自动释放池但没有自动释放方法。
[t setMyNum:[NSNumber numberWithInt:70]];
因此,释放池将不会释放该号码。