簡體   English   中英

Objective-C二傳手內存管理

[英]Objective-C Setter Memory Management

關於Objective-C內存管理仍然有點困惑。 我認為我的困惑源於自動釋放的含義。

NSString *theBackendResponse = [[NSString alloc] initWithData:receivedData encoding:NSASCIIStringEncoding];
NSDictionary *accountDictionary = [theBackendResponse propertyList];
[viewController setAccountDictionary:accountDictionary];

現在,我應該如何處理視圖控制器的setAccountDictionary方法中的accountDictionary? 現在我只是將實例變量“accountDictionary”設置為返回的內容。 我應該將其設置為保留的,然后釋放返回的那個嗎? 考慮到NSS​​tring的propertyList方法是自動釋放的,我的setter代碼塊應該是什么樣的?

順便說一句,如果我發布theBackendResponse,我會丟失accountDictionary嗎? 我假設不...

調用[objectInstance autorelease]會將對象添加到當前的NSAutoreleasePool 當該池收到一條drain消息時,它會向池中的所有對象發送一個release 如果這些對象的retainCount中的任何一個達到0,那么它們將在該點被釋放。 自動釋放的目的是允許您在“將來的某個時間”標記要釋放的對象。 這對於返回新分配的對象但希望釋放它的方法特別有用,這樣調用者就不必獲取返回對象的所有權。 方法可能如下所示:

- (id)myMethod {
    id myObj = [[SomeClass alloc] init];

    ...

    return [myObj autorelease];
}

然后, myMethod的調用者如果想要獲取返回值的所有權,則retain返回值,否則忽略它。 排除當前的NSAutoreleasePoolmyObj將獲得一條釋放消息。 如果沒有其他對象擁有它(即已經發送了retain消息),它將被取消分配。

所有這些都在“可可內存管理編程指南”中進行了解釋。 即使你已經閱讀過它,也總是值得一讀。

那么,回答你的問題:

首先,你應該釋放theBackendResponse 如果不這樣做,你會泄漏內存。 您不需要知道accountDictionary對字符串的作用:如果需要保留引用,它將保留theBackendResponse 你有所有權theBackendResponse因為你alloc倒是它,所以你必須放棄所有權(通過release或通過間接autorelease )。

其次,您必須保留或復制參數setAccountDictionary:如果您想分別保留對該對象或值的引用。 標准的setter方法看起來像這樣(假設你不需要原子語義):

-(void)setAccountDictionary:(NSDictionary*)newDict {
  if(newDict != accountDictionary) {
    id tmp = accountDictionary;
    accountDictionary = [newDict copy]; //Since newDict may be mutable, we make a copy so that accountDictionary isn't mutated behind our back.
    [tmp release];
  }
}

您還必須記得在dealloc方法中release accountDictionary:

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

由於您似乎正在使用NSViewController ,我假設您使用的是Leopard(OS X 10.5),在這種情況下,如果可能,您可能應該使用@property@synthesize d getter / setter。 為此,請添加

@property (copy,readwrite) NSDictionary * accountDictionary; 

聲明到@interface類。 並添加一個@synthesize accountDictionary; 控制器類的@implementation塊中的指令。

通常,一個對象或方法不應該關心另一個對象或方法如何管理內存。 其他人有自動釋放的事實與你無關。 想到所有權的概念更簡單。 所以retain和其他一些方法聲稱所有權, releaseautorelease放棄它。 如果某個對象需要保留對另一個對象的引用,則它應該在需要時聲明所有權。 因此,setter方法通常會保留或復制新值並釋放或自動釋放舊值。

我強烈建議您閱讀Cocoa內存管理指南 它們不是那么長或復雜,理解它們非常重要。

在舊值是唯一擁有新值的對象的情況下,set accessor方法應始終在釋放舊值之前copy / retain傳入值:

-(void)setAccountDictionary:(NSDictionary*)newDict {
    id old = accountDictionary;
    accountDictionary = [newDict copy];
    [old release];
}

如果accountDictionary簡稱newDict並保留計數newDict為1,則調用[accountDictionary release]調用之前[newDict copy]將導致保留計數到了0,因此釋放newDict

作為錯誤代碼的示例,我們發布舊字典然后復制新字典:

-(void)setAccountDictionary:(NSDictionary*)newDict {
    [accountDictionary release];
    accountDictionary = [newDict copy];
}

並具有以下代碼:

NSDictionary *dict = [obj accountDictionary];
[obj setAccountDictionary:dict];

這是設計的,但它證明了在setter中, accountDictionarynewDict引用了同一個實例。 如果保留計數為1,則[accountDictionary release]行將保留計數減少為0,從而從內存中釋放實例。 [newDict copy]現在將引用一個無效的實例。

Apple在實現訪問器時描述了幾個概念: 內存管理訪問器方法
如果你可以使用Objective-C 2.0,我會使用屬性和點語法。 屬性是Objective-C 2.0中的新增功能,並提供自動訪問器生成功能。
在.h文件中:

@property (retain) NSDictionary* accountDictionary;

在實施中:

@synthesize accountDictionary;

Synthesize為NSDictionary生成訪問器方法。 (如果你想提供自己的實現,你也可以這樣做)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM