[英]Objective C NSString* property retain count oddity
我有以下示例類:
Test.h:
@interface Test : UIButton {
NSString *value;
}
- (id)initWithValue:(NSString *)newValue;
@property(copy) NSString *value;
Test.m:
@implementation Test
@synthesize value;
- (id)initWithValue:(NSString *)newValue {
[super init];
NSLog(@"before nil value has retain count of %d", [value retainCount]);
value = nil;
NSLog(@"on nil value has retain count of %d", [value retainCount]);
value = newValue;
NSLog(@"after init value has retain count of %d", [value retainCount]);
return self;
}
其中產生以下輸出:
2008-12-31 09:31:41.755 Concentration[18604:20b] before nil value has retain count of 0
2008-12-31 09:31:41.756 Concentration[18604:20b] on nil value has retain count of 0
2008-12-31 09:31:41.757 Concentration[18604:20b] after init value has retain count of 2147483647
我稱之為:
Test *test = [[Test alloc] initWithValue:@"some text"];
值不應該有1的保留計數嗎? 我錯過了什么?
謝謝你的幫助。
不要看保留計數。 它們沒有用,只會誤導你 - 你不能確定沒有其他東西保留一個物體,你從某個地方得到的物體不會被分享。
相反,專注於對象所有權並遵循Cocoa內存管理規則 。 這樣,無論Cocoa在幕后為您做什么優化,您的內存管理都是正確的。 (例如,將-copy
實現為不可變對象的-retain
。)
此外,理解對象屬性和對象中的實例變量之間的區別至關重要 。 在您的問題代碼中,您要為實例變量賦值。 那個實例變量就是:一個變量。 分配給它將表現得像任何其他變量賦值。 要使用該屬性,必須使用點語法或括號語法來實際調用屬性的setter方法:
self.value = newValue; // this is exactly equivalent to the next line
[self setValue:newValue]; // this is exactly equivalent to the previous line
為點語法和括號語法生成的代碼是相同的,並且都不會直接訪問實例變量。
你傳入一個文字字符串。 編譯器可能會在靜態內存中分配它,並將保留計數設置為最大可能值。
嘗試使用動態分配的字符串,看看會發生什么。
NSString* string = [[NSString alloc] initWithString: @"some text"];
Test* test = [[Test alloc] initWithValue: string];
你傳入一個字符串常量,實際上不能被釋放。 我認為2147483647可能是UINT_MAX,這基本上意味着該對象無法釋放。
我想你想這樣做:
self.value = newValue;
它將調用屬性setter並導致復制發生。 “value = newValue”只是將指針值賦給實例變量。
你有一個不可變字符串的引用。 賦值不需要復制值(字符串數據),因為它是不可變的。 如果你執行一個可變操作,比如value = [newValue uppercaseString],那么它應該將這些位復制到值中,並且值的保留計數遞增。
您不應該關注保留計數,只需遵循Cocoa內存管理規則。 http://iamleeg.blogspot.com/2008/12/cocoa-memory-management.html
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
char *cstr = "this is a c string";
NSString *str = [[NSString alloc] initWithUTF8String:cstr];
NSLog(@"rc1: %d", [str retainCount]);
[pool drain];
return 0;
}
如果運行上面的代碼,它將顯示保留計數1
在Cocoa中,當您在同一區域內請求副本時,許多不可變對象將自行保留。 如果保證對象不會改變(即它的不可變性),則精確復制是多余的。
在Objective-C中,常量字符串類與Cocoa的NSString
類是分開的,盡管它可能是NSString
的子類(我不太確定)。 這個常量字符串類可以覆蓋NSObject
的方法,如retain
, release
和dealloc
這樣它們什么都不做,並且還覆蓋retainCount
這樣它總是返回相同的數字, UINT_MAX
左右。 這是因為在靜態內存中創建了Objective-C常量字符串。 它必須具有Cocoa對象的整體一般行為(當使用Cocoa時),以便它可以添加到數組,用作字典等的鍵,除了它的內存管理,因為它的分配方式不同。
免責聲明:我實際上並不知道我在說什么。
嗯..我們越來越近了。
似乎newValue的保留計數也是2147483647。
我嘗試使用相同的保留計數結果動態分配字符串。
我在這里找到了一篇有用的文章: http : //www.cocoadev.com/index.pl?NSString
FTA:
是否需要釋放@“”返回的NSString,還是自動釋放? 都不是。 @“” - 字符串是類NSConstantString ?,因此就像lisp中的原子一樣; 他們到處閑逛。 也就是說,如果在代碼中的兩個不同位置使用@“cow”,它們將引用同一個對象。 我不認為--release或-autorelease對他們中的任何一個做任何事情。
如果我在屬性上有“復制”,它不應該將目標內存的內容復制到保留計數為1的新內存中嗎? 在這種情況下,復制屬性似乎什么都不做?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.