あなたが正しいので、本は古いドキュメントを参照しているに違いありません。保持カウントについては何も言及していません。ただし、実際にはオブジェクトを保持します。あなたがそれを考える必要がある方法は、(役に立たない)保持数の観点からではなく、むしろ所有権の観点からです。特にARCを使用する場合はそうです。
オブジェクトを に追加すると、オブジェクトNSMutableArray
はそのオブジェクトの所有権を取得します (ARC 用語では、オブジェクトへの強い参照があります)。
「ARCはこれに何をもたらしますか?」
ARC は何も変わりません。ARC が (いくつかの最適化を除いて) 行うことは、ARC を使用せずに自分で追加する場合と同じ release、retain、および autorelease ステートメントを追加することだけです。気にする必要があるのは、オブジェクトを配列に追加すると、少なくとも配列と同じくらい存続することだけです。
メソッドは、渡すオブジェクトを含むarrayByAddingObject:
新しいNSArray
(またはNSMutableArray
) を作成し、渡されたオブジェクトへの強い参照を保持します。作成される実際の配列オブジェクトには、ivar、プロパティ、またはローカル変数のいずれかに割り当てない限り、まだ参照がありません。何に割り当てるかによって、寿命が決まります。
基本的に ARC がなくても、所有権の観点からオブジェクトのライフサイクルを考えるのが最善です。ARC はそれを形式化するだけです。そのため、フレームワークを使用する場合、保持がいつ発生するか発生しないかは関係ありません。所有権を別のオブジェクトに渡すまで、オブジェクトに対してのみ責任があり、フレームワークがオブジェクトを存続させると信頼できます。それが必要な限り。
もちろん、所有権を構成するものを直観する必要があります。たとえば、デリゲート プロパティは、循環保持サイクル (2 つのオブジェクトが互いに保持される) を防ぐために、assign
、または ARCunsafe_unretained
またはであることがよくありますが、保持/強力な場合があるため、ケースバイケースでそれらを調べる必要があります。weak
また、キー値の監視や NSNotification のような場合、監視しているオブジェクトを監視してもオブザーバーは保持されません。
しかし、それらはルールの例外です。通常、強力な参照を想定できます。
上記のこの文について: 「作成する実際の配列オブジェクトには、ivar、プロパティ、またはローカル変数のいずれかに割り当てない限り、まだ参照がありません。割り当て先によって寿命が決まります。」私は説明しようとします:
このコードを実行すると、 (オブジェクト タイプに応じて)[someArray arrayByAddingObject:someObject];
新しいNSArray
またはオブジェクトがインスタンス化されますが、実際には参照に割り当てられていません。つまり、ARC を使用している場合は、その後すぐに解放される可能性があります。ARC を使用していない場合は、autoreleasepool が空になったときに解放されます (おそらく、そのスレッドの実行ループの次の反復で)。NSMutableArray
someArray
代わりにこれを行った場合: NSArray *someOtherArray = [someArray arrayByAddingObject:someObject];
someOtherArray と呼ばれる、新しく作成された配列への参照ができました。この場合、これはローカル変数であり、スコープは{
}
それが存在するセット内にのみあります(したがって、if
ステートメント、ループ、またはメソッド内にある可能性があります。これで他に何もしないと、後で死ぬでしょうスコープが終了します (すぐに死ぬことが保証されているわけではありませんが、それは重要ではありません。それが長く続くと想定することはできません)。
クラスのヘッダーで iVar (インスタンス変数) が宣言されている場合NSArray *someOtherArray;
(ARC ではデフォルトで強力) someOtherArray = [someArray arrayByAddingObject:someObject];
、クラスのどこかで実行すると、オブジェクトは参照 ( someOtherArray = nil
) を削除するか、上書きするまで存続します。参照 ( someOtherArray = someThirdArray
)、またはクラスの割り当てが解除されます。ARC を使用していない場合は、同じ効果を得るためにそれを保持する必要があります (someOtherArray = [[someArray arrayByAddingObject:someObject] retain];
これは基本的に ARC が舞台裏で行っていることです)。
@property (nonatomic, strong) NSArray *someOtherArray
または、同じ効果を達成する代わりにinのようにプロパティを宣言することもできますがself.someOtherArray = [someArray arrayByAddingObject:someObject];
、proprety アクセサー ( setSomeOtherArray:
) を使用するかsomeOtherArray = [someArray arrayByAddingObject:someObject];
、iVar を直接設定するために使用することもできます (@synthesized
それを前提としています)。
または、非 ARC を想定して、 ARC とまったく同じように動作する@property (nonatomic, retain) NSArray *someOtherArray
inのようなプロパティを宣言した可能性がありますself.someOtherArray = [someArray arrayByAddingObject:someObject];
が、iVar を直接設定する場合は、retain を手動で追加する必要があります。
少しでも問題が解決することを願っています。見落としや省略があれば教えてください。
コメントで述べたように、ここでの鍵は、オブジェクトが別のオブジェクトによって所有されていると見なされるかどうかを直感的に知ることです。幸いなことに、Cocoa フレームワークは、安全な仮定を行うことを可能にする一連のかなり厳密な規則に従っています。
NSString
フレームワーク オブジェクトのプロパティ (たとえばtext
a のプロパティなど) を設定すると、UILabel
常にコピーされます (誰かが反例を知っている場合は、コメントまたは編集してください)。そのため、一度渡した文字列について心配する必要はありません。文字列がコピーされるのは、変更可能な文字列が渡された後に変更されないようにするためです。
- 以外の他のプロパティを設定する
delegate
と、(ほぼ?) 常に保持されます (または ARC での強い参照)。
- デリゲート プロパティを設定するときは、(ほとんど?) 常に代入 (または弱参照) して循環保持サイクルを防ぎます。(たとえば、オブジェクト
a
には、強参照されるプロパティb
とb
、強参照されるデリゲート プロパティがあるとします。a
のデリゲートとして設定しb
ます。現在a
、 とb
は両方とも互いに強く参照しており、どちらのオブジェクトも保持カウントが 0 に達することはありません。デリゲートNSURLConnection
はメソッドを介して設定されるため、デリゲートを強く参照する反例です -- 以下の規則を参照してください --NSURLConnection
完了後にnil out または解放する規則ですではなくdealloc
、循環保持を削除します)
- 配列またはディクショナリに追加すると、常に保持されます (または強い参照)。
- メソッドを呼び出してブロックを渡すと、それらは常にコピーされて、スタック (パフォーマンスのために最初に作成された場所) からヒープに移動されます。
- オブジェクトのパラメーターを取り、すぐに結果を返さないメソッドは (常に? そうでないものは考えられません)、メソッドが確実に実行できるように渡すパラメーターをコピーまたは保持 (強い参照) します。彼らと一緒に必要なもの。たとえば
NSURLConnection
、メソッドを介して渡されるためデリゲートも保持されますが、他のオブジェクトのデリゲートプロパティを設定すると、それが規則であるため保持されません。
一貫性を保つために、独自のクラスでもこれらの同じ規則に従うことをお勧めします。
また、すべてのクラスのヘッダーを使用できることを忘れないでください。そのため、プロパティが保持または割り当て (または強いか弱い) であるかを簡単に確認できます。メソッドがそのパラメーターをどのように処理するかを確認することはできませんが、パラメーターは受信者が所有するという慣習があるため、その必要はありません。