5

サードパーティのコードを介してプロジェクトに強制的に導入された場合に対処する以外に、ARCをまだ使用していません。すべての ARC ドキュメントを読みましたが、この質問に対する回答はありません。

でコンパイルされたモジュールで定義されたクラスがある場合、-fobjc-arcARC 対応ではないモジュールでこのクラスから新しいクラスを派生させることはできますか?

私の考えでは、派生クラスがルート クラスの ivar に触れようとしない限り、問題なく動作するはずです。[super dealloc]派生クラスでは、呼び出す dealloc メソッドがあっても問題ないように思えます。

では、その逆はどうでしょうか。非 ARC クラスから ARC 対応クラスを派生させることはできますか? うまくいくはずですよね?

ボーナス ポイント: ARC コードと非 ARC コードを混在させる場合に注意すべき点はありますか?

4

4 に答える 4

6

私が認識している問題はありません。ARCはソースコードプリプロセッサのようなものであり、コンパイル中にメモリ管理呼び出しを追加することを理解する必要があります。リンクフェーズに到達したとき、ARCコードと非ARCコードを実際に区別することはできません。(これはおそらく過度に単純化されていますが、目的に応じて機能するはずです。)派生クラスに正しいメモリ管理があり、スーパークラスに正しいメモリ管理がある場合、結果は正常に機能します。

私が考えることができる唯一の違いは、weakプロパティの処理です。しかし、弱いプロパティを持つARCコードとMRCコードの組み合わせを使用して、バグのあるコードに到達できるかどうかについては、十分にわかりません。

于 2012-06-13T15:36:43.490 に答える
0

はい、ARC 親クラスから非 ARC 祖先を実装することも、非 ARC 親クラスから ARC 祖先を実装することもできます。

実際、ARC はシンタックス シュガーです。または、コンパイル ステップでソース コードを分析し、適切な [release] および [retain] 呼び出しをコードに挿入する単なるプリプロセッサであると言えます。実行時レベルでは何も変更されません (weakプロパティを除く)。

于 2012-06-13T16:06:17.533 に答える
0

これはコメントでしたが、考えてみると、それが言ったことを拡張したいと思います。

通常のサブクラスから ARC クラスを継承しようとしましたか? 私の考えは(試したこともありませんが)、これはうまくいかないということです。まず、ARC クラスに ARC キーワードを使用するパブリック プロパティまたは ivar があるweak場合、ヘッダー ファイルからのコンパイル中にエラーが発生すると思います。第二に、私はそれがどのように機能するかわかりませんdealloc。電話する必要があります[super dealloc]か?知らない。

とにかく、あなたのスーパークラスが ARC なら、どのサブクラスでも ARC を使わないのはなぜですか? そんなことをしても何のメリットもありません。

非 ARC クラスから ARC 対応クラスを派生させることはできますか? うまくいくはずですよね?

私はそれもうまくいかないと言うつもりでしたが、私は間違っていたでしょう. NSObject実質的にすべてのものは、手動参照がカウントされるものから継承する必要があります。

于 2012-06-13T15:36:20.383 に答える
0

ARC はコンパイラがメモリ管理を処理することを意味し、非 ARC はユーザーが処理することを意味しますが、どちらの場合もメモリ管理はまったく同じように機能します。

  • オブジェクトが生き続ける必要がある場合、その保持カウンターが増加します (それがretain機能します) 。
  • オブジェクトが不要になった場合、オブジェクトへの参照が失われる前に保持カウンターが減少します (これが原因ですrelease) 。
  • オブジェクトを使い終わったが、まだ死んではいけない場合、たとえば、メソッドの結果として返す必要がある (そして死んだオブジェクトを返したくない) 場合は、減少する自動解放プールに追加する必要があります。後でその保持カウントを保持します (それは、「将来のある時点でそのオブジェクトをautorelease呼び出す」と言っているようなものです)。release
  • 新しく作成されたオブジェクトの保持カウントは1です。
  • 保持カウントがゼロになると、オブジェクトは解放されます。

すべてを自分で行う場合でも、コンパイラが行う場合でも、それは何の役割も果たしません。コンパイル後、これらのメソッドは ARC でも呼び出されますが、ARC ではコンパイラがいつどのメソッドが呼び出されるかを決定します。追加の魔法があります。たとえば、ARC はオブジェクトをメソッドの結果として返すときに常に自動解放プールにオブジェクトを追加する必要はありません。これは多くの場合最適化して取り除くことができますが、この魔法は呼び出し元が呼び出されたメソッドは両方とも ARC を使用しています。それらのいずれかがそうでない場合は、法線autoreleaseが使用されます (ARC でも以前とまったく同じように機能します)。

注意しなければならない唯一のことは、サイクルを保持することです。ARC を使用するかどうかに関係なく、参照カウントは保持サイクルを処理できません。ここに違いはありません。

落とし穴?フリーダイヤルブリッジングには注意してください。ANSString *と aCFStringRefは実際には同じものですが、ARC は CF ワールドについて認識していませNSStringCFString。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オブジェクトをCFオブジェクトを期待する関数にフィードするときに使用します。ARCは、関数が戻るまでオブジェクトを確実に存続させるためです。たとえば、これは常に安全です。

doSomethingWithString((__bridge CFStringRef)nsstr); 

その行より下のコードがもうアクセスしないため、ARC がnsstrいつでも解放されたとしても、この関数が戻る前に解放されることはなく、関数の引数は定義上、関数が戻るまで存続することが保証されているだけです (関数は文字列を存続させたいので、それを保持する必要があり、保持カウントがゼロにならないため、解放後に ARC は割り当てを解除しません)。

ほとんどの人が苦労しているように見えるのは、ARC オブジェクトをvoid *コンテキストとして渡すことです。これは、古い API で必要になることがありますが、実際には非常に単純です。

- (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 では、コードは次のように動作します。

@interface SomeObject
    @property (assign,nonatomic) id someIVAR;
@end

@implementation SomeObject

- (void)someMethod {
    id someValue = ...;
    self.someIVAR = someValue;
}

非 ARC の ivar はどちらstrongでもないため、プロパティが異なることに注意してくださいweak。それらは何もなく、単なるポインターです (ARC では呼び出され__unsafe_unretained、ここのキーワードはunsafeです)。

そのため、ivar を直接使用し、setter/getter でプロパティを使用せずにそれらにアクセスするコードがある場合、非 ARC から ARC に切り替えると、以前は適切なメモリ管理を行っていたコードでリテイン サイクルが発生する可能性があります。一方、ARC から非 ARC に移行すると、そのようなコードはダングリング ポインター (以前のオブジェクトへのポインターですが、オブジェクトは既に終了しているため、これらはどこにもポイントせず、それらを使用すると予測できない結果になります) を引き起こす可能性があります。予期せず死ぬかもしれません。

于 2017-05-23T18:59:20.830 に答える