ARCは、コンパイラはメモリ管理の面倒を意味し、非ARCは、あなたがそれの世話を意味するが、どちらの場合も、メモリ管理がまったく同じように動作します:オブジェクトは生き続ける必要がある場合は
- を、そのカウンタを保持あなたがオブジェクトで行われている場合
- (つまり
release
が何をするかだ)のオブジェクトがこれ以上必要ない場合は、それへの参照が失われる前に、その保持カウンタが減少している(つまり、retain
が何をするかだ)
- 増加したが、さそれはまだ死んではいけません、例えばメソッドの結果として返す必要がある(そして死んだオブジェクトを返すことを望んでいない)ので、後で保持カウントを減らす自動解放プールに追加する必要があります(つまり、
autorelease
のようになります「将来、そのオブジェクトにrelease
を呼び出してください。」)
- 新しく作成されたオブジェクトの保持カウントは、
1
です。
- 保持カウントがゼロになると、オブジェクトは解放されます。
あなた自身で行っても、コンパイラがそれを行っても、それは何の役割も果たしません。コンパイル後、これらのメソッドはARCでも呼び出されますが、どのメソッドが呼び出されたときにコンパイラがARCを使用して決定しましたか。余計な魔法があります。 ARCは、メソッドの結果として返すときに自動解放プールにオブジェクトを追加する必要はありませんが、これはしばしば最適化されますが、呼び出し側と呼び出されたメソッドの両方が使用している場合にのみ適用されるアーク;そのうちの1つではない場合は、通常のautorelease
が使用されます(ARCでは以前と同じように動作します)。
唯一注意しなければならないことは、サイクルを保持することです。 ARCを使用するかどうかに関係なく、参照カウントでは保持サイクルを処理できません。違いはありません。
落とし穴?フリーダイヤルで慎重にブリッジする。 A NSString *
とCFStringRef
は実際には同じものですが、ARCはCF世界について知らないので、ARCはNSString
を処理しますが、CFString
を処理する必要があります。 ARCを使用する場合は、ブリッジする方法をARCに伝える必要があります。
CFStringRef cfstr = ...;
NSString * nsstr = (__bridge_transfer NSString *)cfstr;
// NSString * nsstr = [(NSString *)cfstr autorelease];
コードは、上記の「ARCは、そのCFString
オブジェクトの所有権を取得し、あなたがそれで行われ次第、それを解放するの世話をしてください」という意味します。コードは、以下のコメントに示されているコードのように動作します。慎重に、cfstr
は少なくとも1の保持カウントを持つ必要があり、ARCはそれを少なくとも1回リリースします。他の方法でラウンド:
NSString * nsstr = ...;
CFStringRef cfstr = (__bridge_retained CFStringRef)cftr;
// CFStringRef cfstr = (CFStringRef)[nsstr retain];
コードは、上記の意味は、「ARCは、私にそのNSString
の所有権を与えてください、私はそれで終わりだ後、それを解放するの世話をします」。もちろん、その約束を守らなければなりません!しばらくしてCFRelease(cfstr)
に電話する必要があります。そうしないと、メモリがリークします。
最後に、キャストされているタイプである(__bridge ...)
があります。所有権は移譲されません。このようなキャストは、キャストの結果を保持しようとすると、ぶら下がるポインタを作成する可能性があるため、危険です。通常は、ARCオブジェクトが関数を返すまでオブジェクトを生かしておくために、ARCオブジェクトがCFオブジェクトを要求する関数にARCオブジェクトを渡すときに使用します。これは、常に安全である:
doSomethingWithString((__bridge CFStringRef)nsstr);
ARCは、その行の下に何のコードが今までもうそれにアクセスしないようにいつでもnsstr
を解放させた場合でも、この関数が戻ってきたし、関数の引数は、である前に、それは確かにそれを解放しません。関数が返るまで有効であることが保証されています(関数が文字列を生きたままにしたい場合、保持しなければならず、ARCは保持カウントがゼロにならないので解放しません)。
あなたは時々古いAPIとを持っているように、ほとんどの人はARCを渡しているに苦労するように見えるものは、void *
コンテキストとしてオブジェクト、まだそれは、実際には死んでシンプルです。
- (void)doIt {
NSDictionary myCallbackContext = ...;
[obj doSomethingWithCallbackSelector:@selector(iAmDone:)
context:(__bridge_retained void *)myCallbackContext
];
// Bridge cast above makes sure that ARC won't kill
// myCallbackContext prior to returning from this method.
// Think of:
// [obj doSomethingWithCallbackSelector:@selector(iAmDone:)
// context:(void *)[myCallbackContext retain]
// ];
}
// ...
- (void)iAmDone:(void *)context {
NSDictionary * contextDict = (__bridge_transfer NSDictionary *)context;
// Use contextDict as you you like, ARC will release it
// prior to returning from this method. Think of:
// NSDictionary * contextDict = [(NSDictionary *)context autorelease];
}
そして、私は本当の大きなする必要が一見するとそれほど明白ではないあなたのためにつかまえます。このコードを考慮してください:
@implementation SomeObject {
id _someIVAR;
}
- (void)someMethod {
id someValue = ...;
_someIVAR = someValue;
}
このコードは、ARCと非ARCでは同じではありません。このコードは、このコードを持っているのと同じように振る舞うARCでのように、ARCでは、すべての変数は、デフォルトでは強いです:
@interface SomeObject
@property (retain,nonatomic) id someIVAR;
@end
@implementation SomeObject
- (void)someMethod {
id someValue = ...;
self.someIVAR = someValue;
}
someValue
がそれを保持します割り当て、オブジェクトが生きているままです!彼らはあるARCに(単なるポインタで、彼らは何もない、非ARCでIVARさんは、どちらもstrong
かweak
あるとしてプロパティは、異なる
@interface SomeObject
@property (assign,nonatomic) id someIVAR;
@end
@implementation SomeObject
- (void)someMethod {
id someValue = ...;
self.someIVAR = someValue;
}
注:非ARCのコードは、このいずれかのように動作します__unsafe_unretained
と呼ばれ、キーワードは不安全です)。
したがって、ivarsを直接使用し、setters/getterでプロパティにアクセスするコードを使用していない場合は、非ARCからARCに切り替えると、メモリ管理が正常に行われていたコードで保持サイクルが発生する可能性があります。一方、ARCから非ARCに移行すると、そのようなコードではポインタ(以前のオブジェクトへのポインタですが、オブジェクトはすでに死んでいるため、どこにも指し示さず、使用すると予測できない結果になります)以前は生き続けることができました。
これはコンセンサスのようです。ご協力いただきありがとうございます。 – TomSwift