0

これは、私が宣言したインターフェイス部分で NSString 型変数の d 保持カウント値を増やすことに関する次のプログラムです。

@property (strong,nonatomic)NSString *str1;
@property (strong, nonatomic)NSString *str2;
-(IBAction)goBtn:(id)sender;

そして、私が以下に定義したind実装部分

- (IBAction)goBtn:(id)sender {
   self.str1=[[NSString alloc]init];
   self.str1=self.str2;
   self.str2=[self.str1 retain];
   self.str2=[[NSString alloc]init];
   self.str2=self.str1;
   self.str1=[self.str2 retain];
   self.str2=[self.str1 retain];
   NSLog(@"retain count is %i", self.str1.retainCount);
   NSLog(@"retain count of str2 is %i", self.str2.retainCount);
}

しかし、出力は保持カウントは0です保持カウントはstr20です

なぜこうなった??コードに何か問題がありますか?

4

2 に答える 2

2

多くのメッセージを nil に送信しているため、保持カウントが 0 になっています。

ここで、変数が変更されたときに変数の新しい値を使用して、コードを再度書き留めました。

str1 と str2 は nil です

self.str1=[[NSString alloc]init];

str1 は空の文字列です

self.str1=self.str2;

str1 はゼロです

self.str2=[self.str1 retain];
self.str2=[[NSString alloc]init];

str2 は空の文字列です

self.str2=self.str1;

str2 はゼロです

self.str1=[self.str2 retain];
self.str2=[self.str1 retain];

最後に、str1 と str2 の両方が nil であり、保持カウントがゼロになります。

しかし、毎回新しい文字列を nil で上書きしなくても、期待どおりの結果が得られません。これを考えてみましょう:

self.str1 = [[NSString alloc] init]
self.str2 = [[NSString alloc] init]

それらの保持カウントを見ると、それぞれに対して 18446744073709551615 (Mac OS X、64 ビットの場合) が得られます。次に、ポインターの値を見ると、両方が等しいことがわかります。したがって、両方の呼び出しで同じ空の NSString オブジェクトが得られます[[NSString alloc] init]

それは実際に理にかなっています。NSString オブジェクトはimmutableです。つまり、いったん作成されると変更できません。したがって、空の文字列の複数の同一のコピーでメモリを浪費しても意味がありません。

これらの共有インスタンスの一部は、retainCount メソッドから可能な最大値を返し、それらがシングルトンであることを示しています。しかし、それらすべてではありません。

したがって、オブジェクトの保持カウントはあまり役に立ちません。いくつかのオブジェクトはそれについて嘘をついています。そして、実際のアプリでは、期待したものではないことがよくあります。自分でオブジェクトを保持していなくても、システムがしばらくオブジェクトを保持することがあります。

しかし、保持/解放メモリ モデルがどのように機能するかを学習しようとしていると思います (これは、ARC を使用している場合でも必要です)。このために、保持カウントを照会することで回避できます。NSObjectただし、保持カウンターで特別なトリックを実行しないため、基本クラスを直接使用する必要があります。また、テスト オブジェクトをいくつかのシステム メソッドに渡すとすぐに、保持カウントが後で予期しないものになる可能性があることに注意する必要があります。実際のアプリで保持カウントをクエリしないように常に注意してください。これは役に立ちません。

于 2013-07-27T07:43:04.110 に答える
0

保持カウントは無意味です。ご心配なく。NSString はクラス クラスタであり、実装の詳細は実際には問題ではないという事実など、多くの複雑な要因に陥ります。

さらに重要なことは、プロパティが正しく宣言されていないことです。

自動保持カウント (ARC)

@property (strong, nonatomic) NSString *ARCString;

保持・解放

@property (retain, nonatomic) NSString *retainString;

さらなる議論

Sven (下記) が指摘しているように、retain と strong は技術的には同義です。ただし、コードが ARC か Retain/Release かを区別することは重要だと思います。一般的なベスト プラクティス:

init でのみ ivar を参照し、_ivar を使用して dealloc を解除します。ARC を使用しない場合は、retain/release の呼び出しを使用します。ARC での割り当て解除は不要です。

- (id)initWithString:(NSString *)string
{
   self = [super init];
   if (self != nil) {
      _retainString = [string retain]; // Adds 1 to retain count
   }

   return self;
}

- (void)dealloc
{
   [_retainString release]; // Decrement retain count by 1

   [super dealloc]; 
}

残りの時間は、self.ivar を使用して getter/setter を呼び出します。これにより、正しい動作が自動的に処理されます。

- (void)doSomethingWithString:(NSString *)string
{
   self.retainString = string; // Adds 1 to retain count
}

宣言されたプロパティで getter/setter をオーバーライドする場合は、_ivar を参照し、retain または release を手動で呼び出します。ARC を使用する場合、retain/release の呼び出しは不要です。

- (void)setRetainString:(NSString *)string
{
    if (_retainString != string) {
       [_retainString release];
       _retainString = [string retain];
    }
}

明らかな方法で何かを台無しにしていないことを確認するために、常にコードを分析する必要があります。多くの場合、ロジックの失敗が明らかになります。

于 2013-07-27T07:16:24.807 に答える