簡體   English   中英

Objective C NSString *屬性保留計數奇數

[英]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的方法,如retainreleasedealloc這樣它們什么都不做,並且還覆蓋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.

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