For example, lets consider following code under 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
In this code, original copyWithZone:
method is implicitly returns a retained object, because it belongs to copy
method family. But my myCopyWithZone:
is not.
I expect crash, but looks like this code works normally. Of course, I can rename my method to avoid confusion. But I am curious what exactly happens under the hood?
As you know, ARC examines the method name, applies the Cocoa memory management naming conventions, and determines how a method should behave. For a method that it's compiling, it makes the method obey those conventions. For a method that it's calling, it assumes the method obeys those conventions.
(One can override the conventions using function attributes, but ignore that for now.)
When ARC is compiling your -myCopyWithZone:
, it determines that such a method should return a +0 reference. When it encounters the call to (apparently) -myCopyWithZone:
, it assumes that method returns a +0 reference. Since those match, it should neither retain or release anything. (Well, it may temporarily retain the result, but it must balance that with an autorelease.) As a result, the actual +1 reference returned by the original -copyWithZone:
survives to the caller and the caller was expecting a +1 reference, so that's all good.
You could probably cause ARC to screw up by calling a different method (which would not be effectively renamed by swizzling) that returns a +1 reference. If it were to return that and since the current method is expected to return a +0 reference, it would autorelease it. The caller would not retain it because it was expecting a +1 reference. So the object would be prematurely deallocated, likely leading to a crash.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With