[英]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”設置為返回的內容。 我應該將其設置為保留的,然后釋放返回的那個嗎? 考慮到NSString的propertyList方法是自動釋放的,我的setter代碼塊應該是什么樣的?
順便說一句,如果我發布theBackendResponse,我會丟失accountDictionary嗎? 我假設不...
調用[objectInstance autorelease]
會將對象添加到當前的NSAutoreleasePool
。 當該池收到一條drain
消息時,它會向池中的所有對象發送一個release
。 如果這些對象的retainCount中的任何一個達到0,那么它們將在該點被釋放。 自動釋放的目的是允許您在“將來的某個時間”標記要釋放的對象。 這對於返回新分配的對象但希望釋放它的方法特別有用,這樣調用者就不必獲取返回對象的所有權。 方法可能如下所示:
- (id)myMethod {
id myObj = [[SomeClass alloc] init];
...
return [myObj autorelease];
}
然后, myMethod
的調用者如果想要獲取返回值的所有權,則retain
返回值,否則忽略它。 排除當前的NSAutoreleasePool
, myObj
將獲得一條釋放消息。 如果沒有其他對象擁有它(即已經發送了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
和其他一些方法聲稱所有權, release
和autorelease
放棄它。 如果某個對象需要保留對另一個對象的引用,則它應該在需要時聲明所有權。 因此,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中, accountDictionary
和newDict
引用了同一個實例。 如果保留計數為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.