2010-02-12 74 views
5

最近有人在堆棧溢出告訴我下面的代碼不漏,該財產處理保留本身:iPhone:這是一個泄漏或不

self.locationManager = [[CLLocationManager alloc] init]; 

中的dealloc:

self.locationManager = nil; 

在.h文件中:

@property (nonatomic, retain) CLLocationManager *locationManager; 

我認爲這是一個明顯的泄漏,並認爲這應該可以修復泄漏:

self.locationManager = [[[CLLocationManager alloc] init] autorelease]; 

但他聲稱不會工作,因爲用他的話說:「你不會自動釋放一個類的屬性。一個屬性的自動生成的訪問定義爲保留會自動處理保持」

,他讓我懷疑他是錯的還是我不明白,在所有的內存管理

編輯1:是的代碼

self.myName=[NSSting stringWithFormat:@"%@ is correct.", @"TechZen"]; 

self.locationManager = [[[CLLocationManager alloc] init] autorelease]; 

內存管理明智的有什麼不同?

這傢伙說第一個是正確的,拒絕第二個。爲什麼第二個是錯誤的?據我可以看到,兩個分配autoreleased實例的一些屬性,但不知何故仍然存在一個固執的論點,第二個是錯誤的。我看不到它,任何幫助都會如此受歡迎。

+1

在你的編輯1上,保留智慧,他們是一樣的。這些對象都只保留一次。所有便利功能都有一個隱含的自動釋放功能。如果你在init語句中沒有看到alloc這個詞,那麼這個變量是自動釋放的。如果你使用alloc,你應該使用autorelease – 2010-02-12 23:23:56

回答

7

計數保留和釋放有助於在這種情況下。這絕對是一個漏洞。你的locationManager對象將被保留2次:一次由alloc/init調用,一次由屬性。將該屬性設置爲nil將只發布一次locationManager

對於編輯1中給出的例子,它們確實是相同的。這聽起來像其他開發人員有一種立即autoreleasing厭惡或不完全明白什麼autorelease做。

0

在下面添加下面這行......它顯然會給你locationManager的保留計數。這會告訴你是否需要手動釋放它。

NSLog(@"retainCount:%d", [locationManager retainCount]); 

編輯:

[locationManager release]; 
+0

不,不,我在概念上問。另外,NSlogging retainCounts不是一個很好的泄漏措施。 – 2010-02-12 15:33:01

+0

哦,好的。那麼最好的做法是你應該在dealloc中這樣做,因爲當autorelease池被耗盡時你的對象不會被釋放。上面編輯。 – Zinc 2010-02-12 15:39:29

+0

從NSObject類的引用:「重要提示:在調試內存管理問題時,此方法[retainCount]通常沒有任何價值[...],您很難從該方法獲得有用的信息。「 – jnic 2010-02-12 15:44:20

1

@jnic:你是驚人的錯誤。 據我瞭解,該屬性的前一個值將發送釋放消息,而不是要分配給該屬性的對象。 所以,是的,建議的代碼確實泄漏,你必須發送一個autorelease消息,就像你想的一樣,ahmet emrah

4

的語義保留屬性選項有:

  • 舊值(如果有的話)得到了釋放消息
  • 新的價值得到了保留消息

因此,在setter之後,CLLocationManager實例的保留計數爲2。一個從分配和一個從保留二傳手。你應該二傳手後立即發送釋放消息:

CLLocationMamnager *aLocationManager = [[CLLocationManager alloc] init]; 
self.locationManager = aLocationManager; 
[aLocationManager release]; 

或者,將其添加到自動釋放池中,以便將至少被最終free'd。就像你自己寫:

self.locationManager = [[[CLLocationManager alloc] init] autorelease]; 

更妙的是,不要使用保留屬性選項。將其保留爲,並將其指定爲(默認值),並且由於您仍在使用保留的對象,因此您將被設置爲去。

+0

非常感謝 – 2010-02-12 19:06:43

-2

好的,這是交易。

當你定義像這樣的屬性...

@property (nonAtomic, retain) NSString myName; 

...因爲屬性的默認命令自己居然喜歡將其定義爲:

@property (nonAtomic, readwrite, retain, getter=getMyName,setter=setMyName) NSString myName; 

當您使用@synthesize myName;在幕後,編譯器生成一個看起來像這樣的吸氣方法:

-(void) setMyName:(NSString *) aString{ 
    if (!(myString==aString) { //test if a string is the same **object** as the current myString 
     if (aString != nil) { // if nil we don't want to send a retain 
      [aString retain]; // increment the retain count by one 
     }   
     [myString release]; //decrement the retain count of the currently assigned string by one. 
     myString=nil; //set the pointer to nil to ensure we don't point to the old string object 
     myString=aString; //assign the newly retained object to the myString symbol  
    } 
} 

正如您所看到的,來自任何來源的任何字符串,任何之前的保留計數,自動釋放或不會自動保留,將在分配時自動保留該方法,並且在分配新值時,該方法將自動釋放該值。多個分配不會堆積保留計數。只要您使用生成的setter,分配的對象(在本例中爲aString)將始終有一個保留計數,以保持它在類中保持活動狀態。

這就是爲什麼你可以做到這一點...

self.myName=[NSSting stringWithFormat:@"%@ is correct.", @"TechZen"];

不必這樣做:

self.myName=[[NSSting stringWithFormat:@"%@ is correct.", @"TechZen"] retain]; 

...而不是擔心,如果該字符串值會突然消失autoreleasepool水渠時。

但是如果你打電話......

[self.myName release]; 

... dealloc以外的任何地方,然後在屬性的對象我可以,除非你堅持不懈地跟蹤它nilled。同樣的道理,如果你打電話給..

[self.myName retain]; 

... ...任何地方,然後在屬性的對象會泄漏(自對象已釋放甚至可能後)。

這就是爲什麼我說永遠保留或自動釋放分配的任何物體或複製到一個屬性中。這不僅沒有意義,而且反作用。因此,當您完成自我對象時,您只想調用發佈版本,因爲setter對保留計數的有效跟蹤意味着即使您仍然需要,您也可以刪除該屬性。

屬性永遠不需要自動釋放,因爲該屬性總是由自身對象保留,並且任何其他對象在使用自身對象的屬性時都應該在內部處理保留。

一旦您瞭解生成的訪問器內部發生了什麼,規則就很明顯。永遠不要明確保留屬性的對象。切勿釋放保存在dealloc中的屬性對象。切勿自動釋放屬性的對象。

這些規則的明顯必然結果是始終在self對象的內部使用self.propertyName引用,以確保自動管理屬性的保留。

+0

Dude, self.myName = [NSSting stringWithFormat:@」%@ is correct。「,@」TechZen 「]; 與 完全相同self.locationManager = [[[CLLocationManager alloc] init] autorelease]; memory management-wise。 我不敢相信你怎麼看不到它。 – 2010-02-12 18:54:53

2

下面的語句被保留的兩倍,因此必須被釋放了兩次:

self.locationManager = [[CLLocationManager alloc] init]; 

這可能是最好的寫法如下:

self.locationManager = [[[CLLocationManager alloc] init]autorelease]; 

現在,這個變量一直保留只有一次,並且你可以在你的類的dealloc函數中釋放它。

此外,如果您運行下面的代碼行,釋放被稱爲:

locationManager = nil; 

由於的LocationManager合成,當你把它設置爲nil,它就會被首次發佈。

此外,如果你做了以下的LocationManager將首先被釋放,然後重置幕後:

self.locationManager = foo; 

最後,下面將與EXC_BAD_ACCESS崩潰,因爲你是一個雙重釋放的LocationManager當你設置到foo:拇指

self.locationManager = [[[CLLocationManager alloc] init]autorelease]; 
[locationManager release]; 
self.locationManager = foo; 
1

規則很簡單:如果一個屬性被標記爲「保留」,總是給它的自動釋放的變量(如果要創建它)當然,除非你還需要在其他地方保留。