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进入__bridge_transfer处理程序,正如这里所建议的那样。但这将 Cocoa 对象视为CFType不是因为它真的被桥接了,而只是为了将保留物塞进它的喉咙。

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

(这个问题中接受的答案给出了一个不同的答案,说__bridge单独是可以的,但在我看来这是错误的,因为原始字符串一旦超出第一个函数的范围就有被释放的风险。 对?)

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

4

2 回答 2

2

跟着你的直觉走。__bridge_retained将对象的管理从 ARC 转移给您,而__bridge_transfer相反,不要担心将对象视为一个CFType- 您并没有真正这样做只是接管管理。

您看到推荐的另一种方法是构建您的代码,以便 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 来实现,将其影响到您之前执行 your 时的值retain,并将其分配给nil您之前执行时的值 yourrelease让字符串离开。


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