目标C内存管理混乱

时间:2009-05-25 18:32:59

标签: objective-c memory-management

我正在阅读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]移动到右边,也没有崩溃???怪异。

3 个答案:

答案 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]];

因此,释放池将不会释放该号码。