5

次のサンプルクラスがあります。

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"];

value の保持カウントを 1 にするべきではありませんか? 私は何が欠けていますか?

ご協力いただきありがとうございます。

4

9 に答える 9

22

保持カウントを見ないでください。それらは役に立たず、誤解を招くだけです。オブジェクトを保持しているものが他にないこと、どこかから取得したオブジェクトが共有されていないことを確認することはできません。

代わりに、オブジェクトの所有権に集中し、 Cocoa のメモリ管理規則に厳密に従ってください。そうすれば、Cocoa が舞台裏でどのような最適化を行っていても、メモリ管理は正しくなります。(たとえば、不変オブジェクトのため-copyだけに実装します。)-retain

さらに、オブジェクトのプロパティとオブジェクト内のインスタンス変数の違いを理解することが重要です。質問のコードでは、インスタンス変数に値を割り当てています。そのインスタンス変数は、まさに変数です。それに割り当てると、他の変数の割り当てと同じように動作します。プロパティを使用するには、ドット構文またはブラケット構文を使用して、プロパティのセッター メソッドを実際に呼び出す必要があります。

self.value = newValue;     // this is exactly equivalent to the next line
[self setValue:newValue];  // this is exactly equivalent to the previous line

ドット構文とブラケット構文で生成​​されるコードは同じで、どちらもインスタンス変数に直接アクセスしません。

于 2009-01-01T01:59:18.467 に答える
11

リテラル文字列を渡しています。コンパイラはおそらくそれを静的メモリに割り当て、保持カウントを可能な最大値に設定します。

代わりに、動的に割り当てられた文字列を試して、何が起こるかを確認してください。

NSString* string = [[NSString alloc] initWithString: @"some text"];
Test* test = [[Test alloc] initWithValue: string];
于 2008-12-31T15:09:16.577 に答える
4

不変の文字列への参照があります。代入は不変であるため、値 (文字列データ) をコピーする必要はありません。value = [newValue uppercaseString] のような変更可能な操作を行う場合は、ビットを値にコピーし、値の保持カウントをインクリメントする必要があります。

于 2008-12-31T16:02:25.863 に答える
3

私はあなたがこれをしたいと思います:

self.value = newValue;

これにより、プロパティ セッターが呼び出され、コピーが発生します。"value = newValue" は単にポインタ値をインスタンス変数に代入します。

于 2008-12-31T15:32:59.680 に答える
3

実際に割り当てを解除できない文字列定数を渡しています。2147483647 はおそらく UINT_MAX だと思います。これは、基本的にオブジェクトを解放できないことを意味します。

于 2008-12-31T15:09:51.240 に答える
2

保持カウントに注意を払うべきではありません。Cocoa のメモリ管理規則に従ってください。http://iamleeg.blogspot.com/2008/12/cocoa-memory-management.html

于 2009-01-01T02:53:04.973 に答える
0

うーん..近づいています。

newValueの保持カウントも2147483647のようです。

同じ保持カウント結果を使用して、代わりに文字列を動的に割り当ててみました。

ここで役立つ記事を見つけました:http: //www.cocoadev.com/index.pl?NSString

FTA:

@ ""によって返されたNSStringを解放する必要がありますか、それとも自動解放されますか?ない。@ ""-文字列はクラスNSConstantString?であるため、lispのアトムのように機能します。彼らはぶらぶらします。つまり、コード内の2つの別々の場所で@ "cow"を使用すると、それらはまったく同じオブジェクトを参照します。-releaseまたは-autoreleaseはどちらにも何もしないと思います。

ただし、プロパティに「コピー」がある場合、ターゲットメモリの内容を保持カウント1の新しいメモリにコピーするべきではありませんか?この場合、copy属性は何もしないように見えますか?

于 2008-12-31T15:44:07.460 に答える
0

Cocoa では、多くの不変オブジェクトは、同じゾーン内でコピーを要求したときにそのまま保持されます。オブジェクトが変更されないことが保証されている場合 (つまり、その不変性)、完全な複製は冗長です。

Objective-C では、定数文字列クラスは Cocoa のNSStringクラスとは別のものですが、Cocoa のサブクラスである可能性がありますNSString(よくわかりません)。この定数文字列クラスは、 や などの のメソッドをオーバーライドしてNSObject、何もしないようにすることも、常に同じ数値を返すようにオーバーライドすることもできます。これは、Objective-C の定数文字列が静的メモリに作成されるためです。Cocoa オブジェクトの全体的な一般的な動作 (Cocoa を使用する場合) を持たなければならないため、配列に追加したり、辞書のキーとして使用したりできます。ただし、割り当てが異なるため、メモリ管理に関しては例外です。retainreleasedeallocretainCountUINT_MAX

免責事項:私は実際に私が話していることを知りません.

于 2009-08-12T14:41:07.530 に答える
0
#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 と表示されます。

于 2009-08-12T14:24:33.860 に答える