使用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
在发布模式下使用Xcode 4.3.2编译时,程序集(我能够理解它)在第二个方法的开头和结尾包含对objc_retain
和objc_release
的调用。发生了什么事?
这不是一个大问题,但在使用Instruments分析对性能敏感的代码时,会出现这种额外的保留/释放流量。看来你可以用__unsafe_unretained
来装饰方法参数,以避免这种额外的保留/释放,正如我在第三个例子中所做的那样,但这样做感觉非常恶心。
答案 0 :(得分:17)
请参阅Objc语言邮件列表中的this reply:
当编译器对此一无所知时 函数或方法的内存管理行为(这种情况发生了 很多),然后编译器必须假设:
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
}
这可能也是您在方法中只有一次调用时看不到额外保留的原因。
答案 1 :(得分:2)
通常,作为参数传递不会增加保留计数。但是,如果您将其传递给类似NSThread
的内容,则会明确记录将保留新线程的参数。
因此,如果没有您打算如何开始这个新线程的示例,我无法给出明确的答案。但总的来说,你应该没问题。
答案 2 :(得分:2)
即使灵魂的答案是正确的,它也应该比它应该更深:
保留,因为传递的引用被分配给一个强变量,即参数变量。这只是保留/释放对的原因。 (将参数var设置为__weak以及会发生什么?)
有人可以优化它吗?这就像优化局部变量上的每个保留/释放对一样,因为参数是局部变量。如果编译器理解方法中的漏洞代码(包括发送的所有消息和函数调用),则可以这样做。这可以应用,很少有人甚至不尝试这样做。 (想象一下,arg指向一个属于一个团体的人(仅),该团体是dealloc&#d; d:该人也将被解除谴责。)
是的,不保留MRC中的args是一种危险,但通常开发人员都知道他们的代码很好,他们在不考虑它的情况下优化了保留/释放。
答案 3 :(得分:1)
它不会在幕后增加。在ARC下,如果对象是强对象,它将保持活着状态直到没有更强的指针。但这实际上与作为参数传递的对象无关。