2010-05-07 143 views
3

我對Objective-C非常陌生,並且正在通過內存管理進行閱讀。我試圖與NSAutoreleasePool玩一下,但不知何故它不會釋放我的對象。Objective-C自動釋放池不釋放對象

我有一個setter和getter類,它基本上設置了一個NSString *名稱。釋放池後,我試圖NSLog的對象,它仍然工作,但我想它不應該?

@interface TestClass : NSObject 
{ 
    NSString *name; 
} 

- (void) setName: (NSString *) string; 
- (NSString *) name; 


@end 

@implementation TestClass 

- (void) setName: (NSString *) string 
{ 
     name = string; 
} 

- (NSString *) name 
{ 
    return name; 
} 

@end 

int main (int argc, const char * argv[]) { 

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

TestClass *var = [[TestClass alloc] init]; 

[var setName:@"Chris"]; 
[var autorelease]; 
[pool release]; 

// This should not be possible? 
NSLog(@"%@",[var name]); 


return 0; 
} 

回答

2

你的代碼有幾個問題。首先,您既不會將copy也不會將retain字符串存儲到name實例變量中。所以,如果字符串是由誰將它存儲到屬性中釋放的,那麼您將留下一個懸而未決的引用。你應該做

- (void) setName: (NSString*) aName { 
    if(name != aName) { 
     if(name) [name release]; 
     name = [aName retain]; // or copy 
    } 
} 

或從一開始就使用屬性。

另外,如果你一直在實例變量對象引用,你應該提供dealloc方法的適當定義:

- (void) dealloc { 
    self.name = nil; 
    [super dealloc]; 
} 

最後,僅僅因爲一個對象已經被釋放,並不意味着,該內存前者的實例被無效。你原來的程序很可能是在一個懸掛參考(var)上調用一個方法,碰巧在這裏運氣確實很好。 (特別是(autorelease不會自動將參考設置爲nil)。

+0

您可以安全地將發佈發​​送到零,因此您的測試該名稱不是零是不必要的。 – JeremyP 2010-05-07 12:52:06

+0

非常感謝您的回答......這正是發生的事情。釋放池之後,我嘗試用TestClass * var1 = [TestClass new]創建一個新對象; [var name]的NSLog爲NULL ....當我爲var1設置名稱[var1 setName = @「John」]時,我實際上可以通過舊對象「var」訪問「John」.... so [var name]實際上打印了「John」... 如果NSZombieEnabled設置爲YES,它會崩潰。這是完美的 經驗教訓。謝謝! – Chris 2010-05-07 13:01:19

5

當您釋放指針var時,您告訴操作系統它所指向的內存可用於重新分配。指針仍然指向該內存,直到它被重新分配爲止,它仍然包含對象的剩餘部分。一旦重新分配,嘗試調用名稱方法將不再有效。

+0

對。 OP可能也想查看設置NSZombieEnabled來檢測嘗試訪問釋放對象並立即崩潰。 – 2010-05-07 12:44:33

+0

同意。它完全依賴運氣,因爲var指向的內存塊仍包含對象的內容。 – JeremyP 2010-05-07 12:49:58

+0

這回答了直接的問題,但也注意@Dirks關於其他問題的答案 – Mark 2010-05-07 12:58:30