2011-04-14 11 views
2

直到昨天,我認爲我已經瞭解了iPhone的內存管理。 那麼這裏是我的問題:用「self.variable = value」設置實例變量兩次會導致內存泄漏?

// .h file 
    @property(nonatomic, retain) NSMutableDictionary *dicParams; 
    @property(nonatomic, retain) NSMutableDictionary *dicReferences; 
    @property(nonatomic, retain) FtMonitorHandler *monitorHandler; 

// .m file 
@synthesize dicParams, dicReferences, monitorHandler; 

- (id)init { 
    self = [super init]; 

    if (self) { 
     self.dicParams = [[NSMutableDictionary alloc] init]; 
     self.dicReferences = [[NSMutableDictionary alloc] init]; 
     self.monitorHandler = [[FtMonitorHandlerService alloc] init]; 
    } 
    return self; 
} 


- (void)dealloc { 
    [monitorHandler release]; 
    [dicParams release]; 
    [dicReferences release]; 
    [super dealloc]; 
} 

如果設置了別的地方,例如

self.dicParams = dicValues; 

的視圖 - 控制的分配後...它會變成一個泄漏

我的設置實例變量的理解與「自我......」是,當前值將被「釋放」,然後設置「保留」。

我嘗試了一下儀器。結果:

-(void)createLeak { 
    self.dicParams = [[NSMutableDictionary alloc] init]; 
    self.dicParams = [[NSMutableDictionary alloc] init]; 
} 

-(void)createAnotherLeak { 
    self.dicParams = [[NSMutableDictionary alloc] init]; 
    self.dicParams = nil; 
    self.dicParams = [[NSMutableDictionary alloc] init]; 
} 

- (void)createWithoutLeak { 
    if(dicParams != nil) [dicParams release]; 
    self.dicParams = [[NSMutableDictionary alloc] init]; 
} 

我錯過了什麼,或者這是行爲,因爲它應該是?

編輯:我試圖實施建議的更改。它工作正常,只要我的變量不是GUI元素。 (UIView的,的UILabel等)

自動釋放將內存警告

- (void)loadView { 
    [super loadView]; 
    // ... here is some other stuff ... 
    self.lblDeparture = [[[UILabel alloc] init] autorelease]; 
} 

- (void)viewDidUnload { 
    [super viewDidUnload]; 
    // Release any retained subviews of the main view. 
    self.lblDeparture = nil; 
} 

- (void)dealloc { 
    [lblDeparture release]; 
    [super dealloc]; 
} 

我不是很確定後會導致應用程序崩潰,但我認爲以下幾行是真正的問題:

CGRect frame = CGRectMake(0, 0, self.view.frame.size.width, INFO_VIEW_HEIGHT); 
UIImageView *imageView = [[UIImageView alloc] initWithFrame:frame]; 

[imageView addSubview:lblDeparture]; 
[lblDeparture release]; // is this correct? 

[self.view addSubview:imageView]; 
[imageView release]; 
+0

爲什麼你使用self.yourObjects,你在同一個類中,而不是保留它(通過調用self.yourObject),你可以嘗試沒有自我。 – Ravin 2011-04-14 06:28:08

+0

如果我用「variable = ...」分配變量兩次,那麼會不會有泄漏,因爲第一個引用將會消失?沒有「self.variable ...」 – user707342 2011-04-14 06:43:42

+0

不,我說你應該嘗試用dicParams = [[NSMutableDictionary alloc] init]; 而不是self.dicParams = [[NSMutableDictionary alloc] init]; 。 – Ravin 2011-04-14 06:46:52

回答

4

如果你初始化你需要自動釋放。

-(void)dontCreateAnotherLeak { 
    self.dicParams = [[[NSMutableDictionary alloc] init] autorelease]; 
    self.dicParams = nil; 
    self.dicParams = [[[NSMutableDictionary alloc] init] autorelease]; 
} 

更容易等同於使用便利存取器。

self.dicParams = [NSMutableDictionary dictionary]; 

如果你想自己處理這個問題。在@synthesize dictParams之上;你也會想創建你自己的setter。

-(void)setDictParams:(NSMutableDictionary*) newDictParams 
{ 
    if (dictParams != newDictParams) 
    { 
     [dictParams release]; 
     dictParams = [newDictParams retain]; 
    } 
} 

這有點簡單。但本質是什麼編譯器添加到@property標籤

+1

更具體地說,當你初始化並傳入setter時,你仍然需要autorelease ... – 2011-04-14 06:28:03

+0

甚至更​​好 - 將它包裝成'[NSMutableDictionary dictionary]' – 2011-04-14 06:30:39

+0

感謝您的回覆。我測試過了,它工作正常。雖然我更喜歡在不使用自動釋放的情況下使用它,並創建一個臨時變量,我之後發佈 – user707342 2011-04-14 06:35:50

0

如果設置您已在property指定retain保留計數變爲1

現在你參考自己的呼叫一個實例變量保留修改創建如「self.variable = value」將retain計數增加1,因此總保留計數變爲2.

因此,現在要釋放它,您需要將保留計數設置爲0.因此,您需要將其釋放兩次。

Hopew有幫助。

+0

+1對於很好的答案。到了這一點,並很好地解釋:) – 2011-04-14 06:35:07

+0

是否有可能使用@property(分配),而不是我喜歡使用「自我...」 – user707342 2011-04-14 06:44:22

+0

@ user707342:不會推薦你分配,但你可以使用下面self.myVariable =無;再次設置它之前.... – Jhaliya 2011-04-14 06:51:23

0

我不確定我是否完全理解這個問題,但是您的第二部分很容易解釋...

- (無效){createLeak

self.dicParams = [[NSMutableDictionary alloc] init]; 

self.dicParams = [[NSMutableDictionary alloc] init]; 

是十分明顯......

,但現在這一個

- (無效){createAnotherLeak

self.dicParams = [[NSMutableDictionary alloc] init]; 

self.dicParams = nil; 

self.dicParams = [[NSMutableDictionary alloc] init]; } 

不釋放第一alloced self.dicParams但將其設置爲無,然後用一個新的重置它,而忘記給它的任何引用。設置爲零不等於釋放。如果你想用autorelease創建第一個,然後將它設置爲零,這是不同的。這應該可以正常工作。這就是你用你的第三個例子做的很棒!

現在爲您inital的問題,它是什麼,當你寫

self.dicParams = dicValues泄漏;

?直到你再次釋放

+0

我不能肯定地說,但儀器標記了另一個有兩個NSArrays並執行self.lines = [NSArray alloc] init]的對象;我的解析器後來用新的值覆蓋了這個數組,導致可疑的泄漏。 – user707342 2011-04-14 06:55:21

0

我建議你仔細閱讀蘋果的內存管理編程指南

變量self.dicParams應該只是保存值。 http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html

這裏都有解釋。

有幾個明顯的錯誤,我可以看到你正在做。

首先,您不應使用initdealloc中的訪問器。

所以,這

- (id)init { 
self = [super init]; 

if (self) { 
    self.dicParams = [[NSMutableDictionary alloc] init]; 
    self.dicReferences = [[NSMutableDictionary alloc] init]; 
    self.monitorHandler = [[FtMonitorHandlerService alloc] init]; 
} 
return self; 
} 

應該

- (id)init { 
self = [super init]; 

if (self) { 
    dicParams = [[NSMutableDictionary alloc] init]; 
    dicReferences = [[NSMutableDictionary alloc] init]; 
    monitorHandler = [[FtMonitorHandlerService alloc] init]; 
} 
return self; 
} 

其次,當你設置一個保留的財產,在你需要釋放無論你將它設置爲。

所以,這

self.dicParams = [[NSMutableDictionary alloc] init]; 

應該

self.dicParams = [[[NSMutableDictionary alloc] init] autorelease]; 

,或者你可以做到這一點

NSMutableDictionary *newDicParams = [[NSMutableDictionary alloc] init]; 
self.dicParams = newDicParams; 
[newDictParams release]; 
+0

感謝您的解釋:-)在這個角度上,你最後描述的方法是否有利於autorelease的分配? – user707342 2011-04-14 07:16:33

+0

手動發佈優於自動發佈,因爲它立即生效。自動釋放的對象在超出範圍時被釋放。 – benwong 2011-04-14 10:15:55

0

通過@synthesize(readwrite, retain, nonatomic)財產所產生的制定者看起來是這樣的:

- (void) setSomething: (id) newSomething; 
{ 
     if (something != newSomething) { 
      [something release]; 
      something = [newSomething retain]; 
     } 
} 

實例變量something指向的舊對象將在新對象被保留時被釋放。

你的錯誤是對象創建。你用[[NSDictionary alloc] init]創建你的字典。此字典的保留計數爲1.您的setter保留該對象,因此新保留計數爲2.當您再次調用setter時,原始字典的保留計數正確地減少 - 再次爲1。爲了釋放字典,你必須再次釋放它。爲此,有autorelease。一段時間後自動釋放的對象將被釋放。所以,正確的代碼來設置你的財產將

self.something = [[[NSDictionary alloc] init] autorelease]; 

甚至更​​好的使用便利性分配器

self.something = [NSDictionary dictionary]; 

你真的應該閱讀和理解蘋果的內存管理指南 - 它在那裏所有的解釋。

順便說一句,我在這裏談到保留計數。考慮它們是可以的,但是你永遠不應該問一個對象它的保留數量,這個價值是沒有用的,因爲它很少會是你想象的。

+0

感謝您的解釋。這會幫助我很多:-) – user707342 2011-04-14 07:23:08