2012-01-24 104 views
0

讓我們說我們有一些代碼,看起來象下面這樣:我已經設置了我的財產保留,即使它設置爲autorelease我應該釋放它嗎?

@interface SomeClass : NSObject 
@property (nonatomic, retain) NSString *someString; 
@end 

@implementation SomeClass 
@synthesize someString; 
-(id)init { 
    if (self=[super init]) { 
     someString = [NSString stringWithString:@"some string"]; 
    } 
    return self; 
} 
@end 

我應該釋放的SomeClass dealloc方法的someString財產,即使someString被設置爲自動釋放,我從來沒有真正保留它我的init方法?如果是這樣,我只需在[super dealloc]之前在-release方法中加上[someString release]即可。正確?

現在我遇到的真正問題是,在使用Cocos2D時,我遇到了矛盾的情況。我的代碼看起來像下面:

@interface SomeLayer : CCLayer 
@property (nonatomic, retain) CCSprite *someSprite; 
@end 

@implementation SomeLayer 
@synthesize someSprite; 
-(id)init { 
    if (self=[super init]) { 
     someSprite = [CCSprite spriteWithFile:@"SomeFile.png"]; 
     [self addChild:someSprite]; 
    } 
    return self; 
} 
@end 

現在,我已經添加someSprite作爲一個孩子到我的層SomeLayer。那麼,我該怎麼做才能確保我在這裏沒有內存泄漏?我能想到以下幾點:

  1. 很顯然,我倒是覺得在SomeLayer-dealloc方法調用[someSprite release]的。但它在[super dealloc](下一行)給我EXC_BAD_ACCESS。很可能是因爲我沒有移除孩子,超類試圖訪問我剛發佈的孩子。
  2. 我在-dealloc方法中調用[self removeChild:someSprite cleanup:YES],該方法會刪除孩子並釋放它。所以我不需要跟進[someSprite release]。但是,嘿,超類CCNode-dealloc方法已經爲我做了。
  3. 我什麼都不做。我根本不會重寫-dealloc方法。那麼,這似乎工作得很好,但它與以下陳述相矛盾:「如果你保留了某些東西,你應該釋放它」。

對於爲什麼我必須在I情況下釋放對象的任何幫助,以及爲什麼不在情況II中處於早期階段將有助於從長遠角度節省大量與內存相關的問題。

感謝

回答

3
someString = [NSString stringWithString:@"some string"]; 

這是不對的。你正在保持一個指向一個自動釋放的對象的指針,這個對象很快就會消失,當你嘗試使用someString指針時,就會發生不好的事情。您應該使用訪問器([self setSomeString:…]),保留自動發佈的值(someString = [… retain])或使用返回保留值的方法(someString = [[NSString alloc] init…])。

在您的實際使用情況下,您應該對精靈進行相同的操作,因爲您過度釋放了精靈,所以您得到了EXC_BAD_ACCESS:您撥打電子郵件release而不會保留該值。閱讀Cocoa Memory Management Guide,從長遠來看,你將爲自己節省很多麻煩。順便說一下,我認爲你的主要問題在於你認爲簡單賦值someString變量保留了賦值。情況並非如此(不是沒有ARC,更確切地說)。賦值給實例變量就是一個普通的賦值。如果您想通過訪問器,則必須發送消息([self setSomeString:…])或使用點符號(self.someString = …)。

+0

你是對分配給'someString'而不是'self.someString'。底層的'@ synthesize'代碼現在保留了我的屬性,我可以用'-dealloc'方法釋放它。很好去:) – Himanshu

1

你只需要釋放你明確分配的對象。你給的例子都沒有分配,所以它們是自動釋放的。如果你想長時間保留一個自動釋放對象,你需要保留它,然後才需要釋放該對象。

此外,如果您有屬性,你應該將它們設置爲無在viewDidUnload

self.someString = nil;

+0

在談論內存管理時,我們應該非常小心,因爲過度簡化很容易。這不是真的,你只需要釋放你分配的內容,至少有一些不符合規則的複製。 – zoul

+0

@zoul我聽到的規則與NARC總結 - 新,Alloc,保留,複製。任何你使用的都需要明確發佈或自動發佈。皺紋是「self.'訪問器上的」隱藏「保留。 – Maple

1

你真的需要讀取內存Management Programming Guide


有兩個四的規則

  • 您可以使用保留對象的所有權。
  • 當你不再需要它,你必須放棄對象的所有權您擁有

當財產申報爲retain,那麼你應該叫release適當的變量。在你的情況你的dealloc應該看起來

- (void)dealloc 
    [someSprite release]; 
    [super dealloc]; 
} 

而且看這個代碼

if (self=[super init]) { 
     someSprite = [CCSprite spriteWithFile:@"SomeFile.png"]; // here you assign pointer to new object 
     [self addChild:someSprite]; // all right, you can use newly created object in this scope 
    } 
// but here that object can be deleted from memory and someSprite can points to nothing 

爲了避免這種情況,你需要保留新創建的精靈

someSprite = [[CCSprite spriteWithFile:@"SomeFile.png"] retain]; 
0
@synthesize someSprite; 

這行使SomeSprite的保留計數爲1 ..在deallo c你釋放它,所以保留回到0 ..對象釋放。

[CCSprite spriteWithFile:@"SomeFile.png"]; 

這是一個自動釋放對象..

當你做

someSprite = [CCSprite spriteWithFile:@"SomeFile.png"]; 

你點someSprite到自動釋放對象..所以都是現在等於..

這條線混亂整個合成點(保留)..現在改變這條線到

[self setsomeSprite] =[CCSprite spriteWithFile:@"SomeFile.png"]; 

現在你只是繼續它是..的方式已經在dealloc中.. someSprite release,一切都會好再次

+0

基本上每當你做一個變量作爲一個屬性...你應該做[self setVariable] =或者self.variable = ..不要簡單地做變量= ...因爲這樣它會混亂內存分配 – Shubhank

相關問題