0

この質問の答えは、ここで同様のスレッドを読んだり、グーグルで検索したりすることで見つけることができると思いますが、私の理解では異常なので、いわば「聞いて」みたいと思います。

これが、前の従業員が書いたコードがあり、私にはかなり奇妙に見える特定の種類の構造がたくさんあるので、「正しいことと間違っていること」を明確にしたいだけです。

例えば

- (void) setWwanServiceId: (NSString *) newValue {
    [wwanServiceId autorelease];
    wwanServiceId = [newValue copy];
}

wwanServiceIdこれがクラスのメンバーです、そしてNSString私にはこれはそれをするための奇妙な方法のように思えます。私が理解している限り、それautoreleaseはオブジェクトに置くことから始まり、基本的に「このオブジェクトが使用されていないように見えるときはいつでも、私のためにそれを解放してください」と言って、コピーは保持カウントを+1します.... wwanServiceId?またはnewValue?私は最初だと思います。

次に、私をさらに混乱させるために、wwanServiceId-stringのライフサイクルをすばやく実行してみましょう。

基本的に、通知を受信すると値が設定され、通知ハンドラーメソッドから上記のメソッドが呼び出されます-setWwanServiceId:。それ以外は、読むためだけにアクセスされるので、いつでもアクセスできると言っても過言ではありません。

  1. オブジェクトに自動解放を配置します
  2. 新しい文字列のコピーを保持する

次に、これにはもう1つの癖があります。これは、私がかなり疑わしいところです。つまり、次の-deallocような方法です。

- (void) dealloc {
    [[self wwanServiceId] release];
    [super dealloc];
}

では、そこで何が起こりますか?私が言っreleasewwanServiceIdように、メモリ管理に触れているのは(私が何も見逃していないが、かなり確信している場合)、自動リリースを入れて保持することだけです。

要約すると、ここでの考え方は、自動リリースを行った後は常に新しいコピーを保持するため、最後にリリースする必要があると考えたということです。それとも、私が考えることができるのはそれだけです。または、万が一の場合に備えて、最終的に追加のリリースを行うのが安全だと感じただけです。

私の知る限り、このセッターが1回呼び出されると、autorelease(将来は-1)になり、retain(+ 1)を実行し、デストラクタが呼び出されると、「最終リリース」(-1)を実行します。

私が理解するのに役立つアイデアや提案(実際に私が間違っていて、メモリ処理がそのまま正しい場合)をいただければ幸いです。

4

4 に答える 4

2

あなたが書いた:

ここで、wwanServiceIdisはクラスのNSStringメンバーであり、私にはこれを行うには奇妙な方法のように思えます。私が理解している限り、それはオブジェクトに自動リリースを配置することから始まります。基本的に、「このオブジェクトが使用されていないように見えるときはいつでも、私のためにリリースしてください」と言って、コピーは保持カウント+1を増やしますon .... wwanServiceId?またはnewValue?私は最初だと思います。

これはあなたの混乱の原因を示しているようです。タイプのオブジェクトへの参照を含むことができるwwanServiceId変数です。変数には、オブジェクトのみが持つ参照カウントはありません。NSString

前の従業員は次のように書いています。

- (void) setWwanServiceId: (NSString *) newValue {
   [wwanServiceId autorelease];
   wwanServiceId = [newValue copy];
}

式の[wwanServiceId autorelease]意味は次のとおりです。に格納されている参照を読み取り、参照が参照しwwanServiceIdているオブジェクトを自動解放します。そのオブジェクトAを呼び出しましょう。重要:これはオブジェクトAを削除しません。それはrelease後の段階としてdになり、その時点で参照が残っていない場合、オブジェクトAは削除されます。

式の[newValue copy]意味:に格納されている参照を読み取り、newValueそれを使用してオブジェクトを見つけ(オブジェクトBと呼びます)、そのオブジェクトのコピーを作成して新しいオブジェクトを生成し(オブジェクトCと呼びます)、新しいオブジェクトへの参照を返します。この新しいオブジェクトはの呼び出し元が所有しているcopyため、その必要はありませんretain

最後に、割り当てはオブジェクトCへの参照をに格納しますwwanServiceId

したがって、最大3つの異なるオブジェクトが関係します。

  1. A:によって参照される元のオブジェクトwwanServiceId。これは、の所有権を削除するために自動解放されwwanServiceIdます。
  2. B:によって参照されるオブジェクトnewValue、これは変更されません。
  3. C:によって所有されているBの新しく作成されたコピーwwanServiceId

なぜコードの「自動リリース」と上記の「最大3つの異なる」のですか?

newValueこのメソッドは、次のように、オブジェクトAを参照して呼び出すことができます。

[self setWwanServiceId:[self wwanServiceId]]

これが発生し、( a)releaseの代わりに使用されautorelease、(b)オブジェクトAへの他の参照がなかった場合、オブジェクトAが削除され、評価されreleaseたときに削除されたオブジェクトが参照されます...ケースは、コピー後まで削除を遅らせます。[newValue copy]newValueautorelease

したがって、前の従業員が書いたことは決して「間違った」ものではありませんが、他の回答のいくつかが示唆しているように、それは珍しいスタイルかもしれません。これが書かれているのを見る別の方法は次のとおりです。

- (void) setWwanServiceId: (NSString *) newValue
{
   NSString *oldValue = wwanServiceId;
   wwanServiceId = [newValue copy];
   [oldValue release];
}

これにより、コピー後に削除が行われるようになります。

HTH。

于 2012-08-30T10:41:10.690 に答える
1

短くて役立つために:

これは間違っています:

- (void) setWwanServiceId: (NSString *) newValue {
    [wwanServiceId autorelease];
    wwanServiceId = [newValue copy];
}

これは正しいです:

- (void) setWwanServiceId: (NSString *) newValue {
    if (newValue != wwanServiceId) {
        [wwanServiceId release];
        wwanServiceId = [newValue copy];
    }
}

簡単に説明すると:

[wwanServiceId autorelease];オブジェクトを自動解放すると、将来の不明な時点で保持カウントが減少するため、は不要な送信メッセージです。そして次の行ではwwanServiceId = [newValue copy];、インスタンス変数を即座に設定しています。したがって、メモリには、自動解放されるオブジェクトと新しいオブジェクトがあります。それらの1つが多すぎます新しいオブジェクトは、IVarのポインターが指している場所です。古いものはおそらくそれへの参照なしであなたのメモリープールで泳いでいます:-)

自動リリースをできるだけ少なくするか、ARCを使用します。

Oh:そして、このdealloc方法では、次のようなメッセージを送信しないでください。

[[self wwanServiceId] release];

このように良い:

[wwanServiceId release];

Appleは、ゲッターやセッターを使用するのではなく、のインスタンスメソッドinitとメソッドを直接操作することを推奨しています。dealloc

于 2012-08-30T09:34:05.723 に答える
0

それをデバッグして見てください。

[wwanServiceId autorelease];

wwanServiceIdにはアドレスがあります。このステートメントはそれを変更しません。ただし、このオブジェクトの保持カウントは減少します。それでおしまい。

wwanServiceId = [newValue copy];

このステートメントは、新しいオブジェクトを作成します。新しいオブジェクトはnewValueのコピーです。オブジェクトのアドレスを比較すると、アドレスinn wwanServiceIdがnewValueのアドレスとは異なり、ステートメントが実行される直前にwwanServiceIdが持っていたアドレスとは異なることがわかります。

で暗黙的に保持されるretainは、copywwanServiceIdに影響しますが、。で作成されたばかりの新しいオブジェクトに影響しcopyます。以前のステートメントで自動解放されたwwanServiceIdオブジェクトには影響しません。

の実行が終了した後のある時点setWwanServiceIdで、古い自動解放されたオブジェクトは消えます。(現在、保持カウントが0であると想定します。他の理由またはエラーのために保持されているために0より大きい場合、保持されたままになり、リークが発生する可能性があります。)

理解したら、deallocメソッドで何が起こっているのか疑問に思うことはもうありません。wwanServiceId解放されます。その保持カウントが1減少することを意味します。それが0の場合、自動的に割り当てが解除されます。そこで自動リリースすることもできます。自動解放との違いは、基本的に、現在のメソッドが実行されている間、自動解放されたオブジェクトがまだ存在し、使用可能であるということです。そのリリースは、後のある時点で有効になります。

ただし、deallocでオブジェクトを自動解放する理由はありません。与えられた例では、セッターでオブジェクトを自動解放する正当な理由すらありませんsetWwanServiceId。両方のメソッドでオブジェクトを直接解放することもできます。

于 2012-08-30T08:40:47.313 に答える
0

ゲッターとセッターwwanServiceIdによってマップされたプライベートivarであると仮定すると、セッターでivarを自動解放することは正しくないと思います。私は次のようにコーディングしたでしょう:wwanServiceIdsetWwanServiceId

- (void) setWwanServiceId: (NSString *) newValue {
    if (newValue != wwanServiceId) {
        [wwanServiceId release];
        wwanServiceId = [newValue copy];
    }
}

つまり、自動解放プールにvarの所有権を与える必要はありません(アプリケーションの最後に削除される可能性があります)。ivarを放すだけです。誰かがそれを使用している場合、問題ありません、それはそれへの強い参照を持っています。それ以外の場合は、割り当てが解除されます。

于 2012-08-30T09:09:19.057 に答える