为什么ARC保留方法参数?

Nic*_*son 18 objective-c clang automatic-ref-counting

使用ARC进行编译时,方法参数通常似乎保留在方法的开头并在结束时释放.这个保留/释放对似乎是多余的,并且与ARC"产生你本来会编写的代码"的想法相矛盾.在那些黑暗的,ARC之前的日子里没有人对所有方法论证进行额外的保留/释放只是为了安全起见,是吗?

考虑:

@interface Test : NSObject
@end

@implementation Test

- (void)testARC:(NSString *)s
{
  [s length];  // no extra retain/release here.
}

- (void)testARC2:(NSString *)s
{
  // ARC inserts [s retain]
  [s length];
  [s length];
  // ARC inserts [s release]
}

- (void)testARC3:(__unsafe_unretained NSString *)s
{
  // no retain -- we used __unsafe_unretained
  [s length];
  [s length];
  // no release -- we used __unsafe_unretained
}

@end
Run Code Online (Sandbox Code Playgroud)

当在Xcode 4.3.2在释放模式编译的组件(例如,我很能理解它)包含到电话objc_retainobjc_release在第二个方法的开始和结束.这是怎么回事?

这不是一个大问题,但是当使用Instruments分析对性能敏感的代码时,会出现这种额外的保留/释放流量.看起来你可以装饰方法参数__unsafe_unretained以避免这种额外的保留/释放,就像我在第三个例子中所做的那样,但这样做感觉非常恶心.

zou*_*oul 18

请参阅Objc语言邮件列表中的回复:

当编译器对某个函数或方法的内存管理行为一无所知时(这种情况会发生很多),编译器必须假定:

1)函数或方法可能完全重新排列或替换应用程序的整个对象图(它可能不会,但它可以).2)调用者可能是手动引用计数代码,因此传入参数的生命周期实际上是不可知的.

鉴于#1和#2; 并考虑到ARC 必须决不允许一个对象被过早地释放,那么这两个假设压力,以保持在对象往往不是通过编译器.

我认为主要的问题是你的方法的主体可能导致争论被释放,因此ARC必须采取防御措施并保留它们:

- (void) processItems
{
    [self setItems:[NSArray arrayWithObject:[NSNumber numberWithInt:0]]];
    [self doSomethingSillyWith:[items lastObject]];
}

- (void) doSomethingSillyWith: (id) foo
{
    [self setItems:nil];
    NSLog(@"%@", foo); // if ARC did not retain foo, you could be in trouble
}
Run Code Online (Sandbox Code Playgroud)

这可能也是您在方法中只有一次调用时看不到额外保留的原因.

  • 简而言之,在第二个例子中,第一次调用`[s length]`可能会导致`s`被释放,除非它首先被保留,所以第二次调用可能在一个不存在的对象上. (5认同)