Swizzling方法,隐含地返回ARC

时间:2016-02-18 23:54:06

标签: objective-c automatic-ref-counting method-swizzling

例如,让我们考虑在ARC下面的代码:

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

@implementation NSDate (MyEvilHack)

+ (void)load {
    Method originalMethod = class_getInstanceMethod(self, @selector(copyWithZone:));
    Method newMethod = class_getInstanceMethod(self, @selector(myCopyWithZone:));
    method_exchangeImplementations(originalMethod, newMethod);
}

- (id)myCopyWithZone:(NSZone *)zone {
    id result = [self myCopyWithZone:zone];
    // do customization
    return result;
}

@end

在此代码中,原始copyWithZone:方法隐式返回一个保留对象,因为它属于copy方法族。但我的myCopyWithZone:不是。

我希望崩溃,但看起来这段代码正常工作。当然,我可以重命名我的方法以避免混淆。但我很好奇在引擎盖下究竟发生了什么?

1 个答案:

答案 0 :(得分:4)

如您所知,ARC检查方法名称,应用Cocoa内存管理命名约定,并确定方法的行为方式。对于它正在编译的方法,它使该方法遵循这些约定。对于它正在调用的方法,它假定该方法遵循这些约定。

(可以使用函数属性覆盖约定,但暂时忽略它。)

当ARC正在编译-myCopyWithZone:时,它确定这样的方法应返回+0引用。当遇到(显然)-myCopyWithZone:的调用时,它假定该方法返回+0引用。由于这些匹配,它既不应该保留或释放任何东西。 (好吧,它可能暂时保留结果,但它必须与自动释放相平衡。)因此,原始-copyWithZone:返回的实际 +1引用存活到调用方并且调用者期待+1参考,所以这一切都很好。

你可能会通过调用一个返回+1引用的不同方法(不会被swizzling有效地重命名)来使ARC搞砸。如果要返回它并且由于当前方法预期返回+0引用,它将自动释放它。调用者不会保留它,因为它期望+1引用。因此,该对象将过早解除分配,可能导致崩溃。