重排方法,在 ARC 下隐式返回保留对象



例如,让我们考虑 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:不是。

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

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

(可以使用函数属性覆盖约定,但现在忽略它。

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

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

相关内容

  • 没有找到相关文章

最新更新