5

手動のメモリ管理では、このパターンをかなり頻繁に使用します。

NSString * myStr = /* some local object */
[UIView beginAnimation:@"foo" context:(void *)[myStr retain]];

そして、後で非同期に:

- (void)animationDidStop:(NSString *)anim finished:(NSNumber *)num context:(void *)context
{
    NSString * contextStr = (NSString *)context;
    // ...
    [contextStr release];
}

つまり、不透明なコンテキストとして使用されるオブジェクトの有効期間を手動で管理しました。(これは古い UIView アニメーションにも当てはまりますが、私が使用する他の種類の API にも当てはまります。)

ARC の下では、私の本能は、ここで提案されているように、ハンドラーに__bridge_retained出入りしたいということです。しかし、これは Cocoa オブジェクトを として扱います。これは、実際にブリッジされているからではなく、保持を喉に突き刺すためだけです。__bridge_transferCFType

これは有効で、これはスタイル的に受け入れられますか? そうでない場合、より良い*解決策は何ですか?

(この質問で受け入れられた回答は、単独で問題ないと言って別の回答を与えます__bridgeが、最初の関数で範囲外になるとすぐに元の文字列の割り当てが解除されるリスクがあるため、それは間違っているように思えます。 右?)

※「代わりにブロックベースのアニメーションを使用してください」とは言わないでください。(それは私が尋ねていることではありません。)

4

2 に答える 2

2

あなたの本能に従ってください。__bridge_retainedオブジェクトの管理をARCからあなたに移します__bridge_transferが、その逆ですが、オブジェクトをオブジェクトとして扱うことを心配する必要はありCFTypeません.管理を引き継ぐだけではありません.

推奨されるもう 1 つのアプローチは、ARC が管理を保持するようにコードを構築することですが、これは不自然に見えてしまいます (そして面倒になります)。使用している API に設計どおりの値を維持させることはクリーンです。管理が API に渡され、ARC に返されるコードを適切にコメントするだけです。

于 2012-10-10T00:22:19.937 に答える
1

__bridge_retained/を使用しても問題ない__bridge_transferように思えます (所有権を CoreFoundation または C コードまたは自分自身に譲渡することはまったく同じで、ある時点でオブジェクトの所有権に責任があることを ARC に伝え、後で所有権を ARC に返すだけです)、代わりに、必要に応じstrongてどこかとして使用するオブジェクトの参照を保持しcontextて、ARC がそのメモリを再利用しないようにすることができます。

これは@property(strong)、たとえば、クラスで a を使用して、以前に実行したときに値に影響を与え、以前に実行したときににretain割り当てて、文字列を解放することで実現できます。nilrelease


同じクラスで複数のコンテキストを保持する必要がある場合は、NSMutableArray各コンテキストのプロパティを宣言する代わりに、コンテキスト文字列を保持する を使用するオプションを選択できます。

@interface YourClass ()
@property(strong) NSMutableArray* runningAnimationContexts;
@end

@implementation YourClass
-(id)init {
  self = [super init];
  if (self) {
    self.runningAnimationContexts = [NSMutableArray array];
  }
  return self;
}

-(void)someMethod
{
  // Example with two different parallel animations using old API

  NSString * myStr = /* some local object */
  [self.runningAnimationContexts addObject:myStr]; // ~ retain
  [UIView beginAnimation:@"foo" context:(__bridge)myStr];
  ...
  [UIView commitAnimations];

  NSString * myStr2 = /* some other local object */
  [self.runningAnimationContexts addObject:myStr2]; // ~ retain
  [UIView beginAnimation:@"foo2" context:(__bridge)myStr2];
  ...
  [UIView commitAnimations];

}
- (void)animationDidStop:(NSString *)anim finished:(NSNumber *)num context:(void *)context
{
  NSString * contextStr = (__bridge NSString *)context;
  // ...
  [self.runningAnimationContexts removeObject:contextStr]; // ~ release
}
@end
于 2012-10-09T23:44:13.207 に答える