【譯】蘋果官方手冊:高級內(nèi)存管理編程手冊2:內(nèi)存管理方法

內(nèi)存管理使用的基本模式,引用計數(shù),它的運(yùn)行環(huán)境是由NSObject協(xié)議(協(xié)議聲明程序接口,采用這個協(xié)議的類需要實現(xiàn)這個接口)和一個標(biāo)準(zhǔn)方法命名約定提供的。NSObject類同時也定義了一個dealloc方法,這個方法會在對象被釋放的時候自動調(diào)用。本文將討論那些在Cocoa程序的內(nèi)存管理中你必須要了解的基本規(guī)則,并會提供一些正確使用的實例。

基本內(nèi)存管理規(guī)則

內(nèi)存管理的模式是建立在對象的依賴關(guān)系上的。任何一個對象都可能被一個或多個對象擁有。當(dāng)對象被至少一個對象擁有時,這個對象就是存在的。如果一個對象不被任何對象擁有,那么系統(tǒng)將會自動地將這個對象回收。為了確保明確地了解什么時候擁有一個對象什么時候沒有,Cocoa定義了如下規(guī)則:

  • 當(dāng)你創(chuàng)建對象時,你擁有它
    當(dāng)你使用開頭為“alloc”、“new”、“copy”或 “mutableCopy” 之類的方法(例如,alloc, newObject 或者mutableCopy)創(chuàng)建一個對象時。
  • 你可以使用retain來保持擁有狀態(tài)
    當(dāng)方法接收到一個對象,或者這個方法同時安全地將對象返回給調(diào)用者,這個對象通常是有效的。在以下兩種情況下,你需要使用retain:(1)在實現(xiàn)一個訪問方法或init方法時,你需要保持當(dāng)前的對象作為一個屬性值;或者(2)避免某些操作的副作用導(dǎo)致對象不可用(具體描述參考避免導(dǎo)致你正在使用的對象被釋放)。
  • 當(dāng)你不再需要某個對象時,你必須放棄對對象的擁有權(quán)
    你可以通過給對象發(fā)送一個release消息或autorelease消息來放棄對象的擁有權(quán)。在Cocoa的術(shù)語中,放棄一個對象的擁有權(quán)被稱作“釋放”一個對象。
  • 你絕不能放棄一個你沒有擁有的對象的擁有權(quán)
    根據(jù)上方的規(guī)則,這條規(guī)則是必然的。

一個簡單的實例

為了說明這些規(guī)則,研究如下代碼片段:
{ Person *aPerson = [[Person alloc] init]; NSString *name = aPerson.fullName; [aPerson release]; }
Person對象使用alloc方法被創(chuàng)建,所以當(dāng)不在需要使用它的時候,我們隨后給它發(fā)送了release消息。person對象的name屬性沒有被任何具有擁有性質(zhì)的函數(shù)獲取,所以它沒有被發(fā)送release消息。需要注意的是,這個例子使用的是release而不是autorelease。

使用autorelease發(fā)送一個延遲釋放消息

在你需要發(fā)送一個延遲的釋放消息時,你可以使用autorelease——典型場景是從方法中返回一個對象。例如,你會這樣來實現(xiàn)fullName方法:
- (NSString *)fullName { NSString *string = [[[NSString alloc] initWithFormat:@"%@ %@", self.firstName, self.lastName] autorelease]; return string; }
根據(jù)基本規(guī)則,你并不擁有stringWithFormat:返回的字符串,所以你可以安全地從這個方法中返回這個字符串。
相比之下,下邊的這種實現(xiàn)是錯誤的:
- (NSString *)fullName { NSString *string = [[NSString alloc] initWithFormat:@"%@ %@", self.firstName, self.lastName]; return string; }
根據(jù)命名慣例,沒有任何跡象表明fullName的調(diào)用者需要擁有返回的字符串。調(diào)用者沒有義務(wù)釋放返回的字符串,這將導(dǎo)致內(nèi)存泄漏。

你并不擁有返回的引用對象

Cocoa中的一些方法生命了對象將以引用的方式返回(它們具有類型為ClassName **id *的返回值)。一個典型的模式是當(dāng)異常出現(xiàn)時,使用一個包含了異常信息的NSError對象,例如initWithContentsOfURL:options:error:(NSData)和initWithContentsOfFile:encoding:error:(NSString)。
著這些情況下,同樣的規(guī)則適用于已經(jīng)被討論過的情況。當(dāng)你調(diào)用這種方法的時候,你并沒有新建NSError對象,所以你并不擁有它。所以你沒必要釋放他。舉例如下:
NSString *fileName = <#Get a file name#>; NSError *error; NSString *string = [[NSString alloc] initWithContentsOfFile:fileName encoding:NSUTF8StringEncoding error:&error]; if (string == nil) { // 解決異常…… } [string release];

實現(xiàn)dealloc方法來放棄對象的擁有權(quán)

NSObject類定義了一個方法,dealloc,在當(dāng)一個對象沒有任何擁有者并且內(nèi)存被回收——在Cocoa術(shù)語中叫做“釋放”或“反分配”——時自動被調(diào)用。dealloc方法所扮演的角色是釋放該對象占用的內(nèi)存,并釋放所有它保持的資源,包括其所擁有的對象的實例變量。
下面的實例演示了對Person類的dealloc方法的一種實現(xiàn):
@interface Person : NSObject @property (retain) NSString *firstName; @property (retain) NSString *lastName; @property (assign, readonly) NSString *fullName; @end

@implementation Person

- (void)dealloc { [_firstName release]; [_lastName release]; [super dealloc]; } @end

重要提醒:絕不要直接調(diào)用其它類的dealloc方法。
你必須在實現(xiàn)的最后調(diào)用超類的實現(xiàn)。
你不應(yīng)將系統(tǒng)資源的管理捆綁在對象的生命周期上。參考不要使用dealloc管理稀有資源。
當(dāng)一個應(yīng)用在終止的時候,對象也許不會發(fā)出dealloc消息。因為在推出之前,程序的內(nèi)存會被自動清理,允許操作系統(tǒng)清理資源比調(diào)用所有的內(nèi)存管理方法更簡潔有效。

核心基礎(chǔ)類庫使用相似但不同的規(guī)則

在核心基礎(chǔ)類庫對象中,內(nèi)存管理的機(jī)制很相似(參考核心基礎(chǔ)類庫的內(nèi)存管理程序設(shè)計)。但Cocoa和核心基礎(chǔ)類庫的命名管理是不同的。具體來說,核心基礎(chǔ)類庫的創(chuàng)建規(guī)則(參考創(chuàng)建規(guī)則)并不支持返回Objective-C對象的方法。例如,下面的代碼片段,你沒有責(zé)任放棄對myInstance的擁有權(quán)。
MyClass *myInstance = [MyClass createInstance];

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容