2009-05-25 66 views
1

我正在閱讀memory management的蘋果文檔,遇到了一些我只是不明白的東西。基本上,我不明白爲什麼不需要通過「getter」方法保留一個實例變量。我寫了這個小程序來看看會發生什麼。我以爲會有一個崩潰,但我顯然錯過了一些東西。Objective C內存管理混亂

// 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仍然在附近的原因是因爲它還沒有從池中autoreleased。但即使在NSLog消息之前移動[pool drain]之後,也沒有崩潰?奇怪的。

回答

5

由於您沒有明確釋放任何對象,因此在釋放autorelease池之前沒有任何對象被釋放。嘗試在最後的NSLog調用之前插入[p drain]。它應該會導致NSLog調用崩潰。

此外,如果您未在setMyNum:方法中保留NSNumber,則會發現如果在分配tempNum之前添加[p drain],它將會崩潰。

爲了澄清原始問題,調用getter方法不會(也不應該)暗示調用方想要獲取所有權(即保留)變量。如果是這樣的話,這個代碼將泄漏:

NSLog("Number is %@", [t myNum]); 

而且,看來NSNumber的具有優化功能的小數目,他們緩存的NSNumber對象,保留一個額外的拷貝,並返回該版本。因此對於小常量,[NSNumber numberWithInt: N]將返回一個帶有2個參考計數的對象(可通過[theNumber retainCount]獲得)。爲了明確地看到會發生什麼,在程序中使用一個更大的常量,NSNumber將保留一個引用計數爲1的「新鮮」對象(這也將被自動釋放)。

+0

但在我的setMyNum中,我明確地調用retain和release。我呼籲釋放後,舊號碼會發生什麼? – esiegel 2009-05-25 18:51:52

+1

版本不會釋放對象,它只是從該對象的「保留計數」中減去一個。只有當保留計數達到0時,對象纔會被釋放。在你的情況下,編號(代表5的NSNumber)在創建後有一個直接的保留計數,然後當它在Test對象中設置時增加到2,然後當另一個NSNumber(代表7)獲得時遞減到1在Test對象中設置。 – harms 2009-05-25 18:56:43

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方法臨時號碼獲取尚未釋放,直到[p drain]數所以不會有任何崩潰。

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];數所以不會有任何崩潰。即使下面的代碼不會崩潰,因爲有autorelease池但沒有autorelease方法。

[t setMyNum:[NSNumber numberWithInt:70]]; 

因此釋放池將不會釋放該數字。