4

手動保持リリース コードを ARC に変換しようとしています。

リターン ポインターの値が CFTypeRef に格納されている Objective-C の便利なコンストラクターがある場合、フリー ブリッジを使用する正しい方法を見つけるのに苦労しています。

MRR を使用した既存のコード:

@interface SourceItemCell UITableViewCell
{
  CATextLayer *mSourceText;
}

@implementation SourceItemCell
- (id)init
{
  self = [super init];
  mSourceText = [CATextLayer layer];

  // key line I'm wondering about:
  mSourceText.font = [UIFont fontWithName:@"HelveticaNeue" size:12.0];

  [[self contentView].layer addSublayer:mSourceText];
  return self;
}

ドキュメントを調べなくても済むように、CATextLayer のフォント プロパティは CFTypeRef 型になっています。

私のオプションは次のようです:

mSourceText.font = (__bridge CFTypeRef)[UIFont fontWithName:@"HelveticaNeue" size:12.0];

また:

mSourceText.font = (__bridge_transfer CFTypeRef)[UIFont fontWithName:@"HelveticaNeue" size:12.0];

また:

mSourceText.font = (__bridge_retained CFTypeRef)[UIFont fontWithName:@"HelveticaNeue" size:12.0];

これが私の考えです。私が見つけたフリーダイヤル ブリッジングの最も明確なガイドはhttp://www.mikeash.com/pyblog/friday-qa-2011-09-30-automatic-reference-counting.htmlです。Objective-C 型から C 型へのキャストの同様の例があり、それについて彼は次のように書いています。

__bridge_retained を使用することで、所有権をシステムから私たちの手に移すように ARC に指示できます。所有権が譲渡されたので、他の CF コードと同様に、オブジェクトの処理が完了したらオブジェクトを解放する必要があります。

...そうでなければ、__bridge だけを使用すると、ARC は CFTypeRef のアカウントのメモリを保持しようとはしません。

そこで、私が考える最も賢明な方法は次のとおりです。

mSourceText.font = (__bridge_retained CFTypeRef)[UIFont fontWithName:@"HelveticaNeue" size:12.0];
... // At some later point
CFRelease(mSourceText.font);

もしそれが正しければ、リリースしても安全だと確信できる時期についてはまだかなりはっきりしていません。

結論として、私の実際の質問は次のとおりです。

  1. 提案されたコードは正しいですか?
  2. このオブジェクトはどこで CFRelease する必要がありますか? SourceItemCell の dealloc 関数では?

関連する質問が私の質問に答えたとは思わなかった理由は次のとおりです。

  1. 自動解放されたオブジェクトを Core Foundation にブリッジする場合、__bridge または __bridge_retained を使用する必要がありますか? Objective-C の便利なコンストラクタが前の行の Objective-C 変数に明示的に保存されていることが重要かどうかはわかりません。また、承認された回答では、Cオブジェクトの「ライフサイクルを管理したい場合」にのみ__bridge_retainedを使用するように言われていますが、これは間違っていると思います...ライフサイクルを自分で管理する必要があるため、多くの人が__bridge_retainedを使用しているように感じます.
  2. どこで、どのように __bridge承認された回答には役立つ要約がありますが、保持されていない例に焦点を当てています。

PS。私は Helvetica を使用しているので、私を判断しないでください... :)

編集:

__bridge_retained を使用して静的アナライザーを実行すると、次のような苦情が寄せられます。

静的アナライザーの苦情

「プロパティは、保持カウントが +0 の Core Foundation オブジェクトを返します。この時点で呼び出し元が所有していないオブジェクトの参照カウントが正しく減少しません。」

(mDelegate と IS_ARC の行は、この問題とは無関係だと思います。)

だから、私が根本的に正しく理解していないことがあります...

4

2 に答える 2

4

まず、元のMRRコードが正しいかどうかです。UIFontドキュメントによると、オブジェクトを のfontプロパティに割り当てることはできませんがCATextLayerCTFontRef、またはCGFontRef. このようなものはうまくいくはずです:

 CGFontRef font = CGFontCreateWithFontName(CFSTR("HelveticaNeue"));
 mSourceText.font = font;
 CGRelease(font);
 mSourceText.fontSize = 12.0;

ブリッジングに関するあなたの質問に答えるために、 to をキャストするのが正しいと仮定しましょう(私そうではないと確信しています!)。次に、次を使用します。UIFont *CGFontRef__bridge

 mSourceText.font = (__bridge CGFontRef)[UIFont fontWithName:@"HelveticaNeue" size:12.0];

その理由は、 のCATextLayerオブジェクトがmSourceTextフォント自体を保持するため、そうする必要がないからです。

ただし、間に保管する場合は注意が必要ですCGFontRef。次のようなコードは危険です。

CGFontRef fontRef = (__bridge CGFontRef)[UIFont fontWithName:@"HelveticaNeue" size:12.0];
mSourceText.font = fontRef;

ARC はUIFont、最初と 2 番目のステートメントの間でオブジェクトを解放する場合があるため、fontRefポインターは割り当て解除されたオブジェクトを指します。コードを 2 つのステートメントで記述したい場合は、割り当てられるまでオブジェクトを保持し、その後解放する必要があります。

CGFontRef fontRef = (__bridge_retained CGFontRef)[UIFont fontWithName:@"HelveticaNeue" size:12.0];
mSourceText.font = fontRef;
CFRelease(fontRef);
于 2013-05-30T14:58:43.897 に答える
2

タモの答えに同意します。

__bridge_transfer__bridge_retained:CFBridgingRelease()とには、それぞれカバー関数を常に使用することをお勧めしますCFBridgingRetain()。それらはあなたの考えを明確にするのに役立ちます。

CFBridgingRelease()の資格がある場合にのみ使用できますCFRelease()。そしてCFBridgingRetain()、それが理にかなっている場所でのみ使用する必要がありますCFRetain()

メソッド+[UIFont fontWithName:size:]は返されたオブジェクトの所有権をあなたに与えないので、あなたはそれを解放する資格がCFRelease()ありませんCFBridgingRelease()

もう 1 つのケースを考えてみましょう。オブジェクトをプロパティ セッターに渡す前に、あなたCFRetain()または-retainオブジェクトを渡しますか? 少し異なるケースを考えてみましょう。Core Foundation 型ではなくfont、 type のプロパティを持つクラスを想像してください。UIFont*これを行いますか(MRRの下で):

someObject.font = [[UIFont fontWithName:@"HelveticaNeue" size:12.0] retain];

?

うまくいけば、あなたはしてはいけないことを知っています。そのオブジェクトを解放してバランスを保つ適切な方法がありません。(そして、いいえ、後で行うの[someObject.font release]は正しくありません。プロパティは、setter に渡された getter から同じオブジェクトを返さない場合があります。setter は、コピーを作成するか、渡された値に基づいて新しい値を計算する場合があります。または、それ以外は何でも好きです。)

いずれにせよ、-retainそのような状況に陥らないことに気がついたら、そうはならずCFRetain()、そうすべきではないことに気がつきますCFBridgingRetain()

最後に、物事を考えるもう 1 つの方法は、メモリ管理の局所性です。セッターの呼び出し元は、渡されたオブジェクトを固定する責任はありません。セッターの実装は、実際に渡されたオブジェクトへの参照を保持することになる場合(そうでない場合があります)、それに対して責任があります。メソッドまたはクラスを作成する場合、他のメソッドまたはクラスではなく、そのメソッドまたはクラスのメモリ管理を処理する必要があります。他のメソッドまたはクラスが独自の責任を負うことを期待する必要があります。(この原則は、ARC でコンパイルされたコードと MRR コードの混合を可能にするものでもあります。)

于 2013-06-01T14:17:05.857 に答える