在ARC下将对象安全地作为不透明的上下文parameter passing

在手动内存pipe理下,我经常使用这个模式:

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

然后,后来和asynchronous:

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

即我手动pipe理用作不透明上下文的对象的生命周期。 (对于旧的UIViewanimation,对于其他types的API也是如此。)

在ARC下,我的本能就是我想要__bridge_transfer在处理程序中进入__bridge_transfer , 正如这里所build议的那样 。 但是这把cocoa物体当作CFType并不是因为它是真的桥接的,而仅仅是为了把一个可卡因放在喉咙里。

这是否有效,这在风格上是可以接受的? 如果没有,最好的解决scheme是什么?

( 在这个问题上接受的答案给出了一个不同的答案,说只有__bridge是可以的,但是在我看来是错误的,因为原来的string在第一个__bridge就有可能被释放function,对吗?)

*请不要说“改为使用基于块的animation”。 (这不是我问的。)

去你的本能。 __bridge_retained将对象的pipe理从ARC转移给你,而__bridge_transfer则反过来,不要担心把对象当作CFType – 你并不是真的只是接pipepipe理。

你所看到的另一种方法是build立你的代码,以便ARC保留pipe理,但是这很容易被人发现(而且变得混乱)。 拥有你所使用的API,保持价值,因为它的目的是干净的; 只要将pipe理权移交给API,然后将其返回给ARC,就可以对代码进行适当的评论。

即使使用__bridge_retained / __bridge_transfer对我来说看起来不错(把所有权转让给CoreFoundation或者任何C代码或者与你自己完全一样,你只需告诉ARC你在某个时间点对对象所有权负责,并且将所有权归还给ARC ),如果您愿意,您可以在对象上保留一个strong引用,以便ARC不会回收它的内存。

这可以通过在你的类中使用一个@property(strong)来实现,例如,当你以前做过retain时候影响它的值,当你之前做了release让string去的时候把它分配给nil


请注意,如果您需要在同一个类中保留多个上下文,则可以select使用保留上下文string的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