2016-02-18 12 views
5

Zum Beispiel zurückkehren, kann folgenden Code unter ARC betrachten:Swizzling Methoden, die implizit ein beibehaltene Objekt unter 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 diesem Code ursprüngliche copyWithZone: Methode zurückgibt implizit ein beibehaltene Objekt, weil es zu copy gehört Methodenfamilie. Aber meine myCopyWithZone: ist nicht.

Ich erwarte Absturz, aber sieht aus wie dieser Code normal funktioniert. Natürlich kann ich meine Methode umbenennen, um Verwirrung zu vermeiden. Aber ich bin gespannt was genau unter der Haube passiert?

Antwort

4

Wie Sie wissen, überprüft ARC den Methodennamen, wendet die Namenskonventionen für die Cocoa-Speicherverwaltung an und legt fest, wie sich eine Methode verhalten soll. Bei einer Methode, die kompiliert wird, muss die Methode diese Konventionen beachten. Für eine Methode, die aufgerufen wird, wird davon ausgegangen, dass die Methode diesen Konventionen entspricht.

(Man kann die Konventionen außer Kraft setzen Funktion Attribute, aber das jetzt ignorieren.)

Wenn ARC ist Ihr -myCopyWithZone: kompilieren, es feststellt, dass ein solches Verfahren eine +0 Referenz zurückgeben sollte. Wenn der Aufruf an (scheinbar) -myCopyWithZone: auftritt, nimmt es an, dass Methode eine + 0-Referenz zurückgibt. Da diese übereinstimmen, sollte es nichts behalten oder freigeben. (Nun, es kann vorübergehend das Ergebnis behalten, aber es muss das mit einer Autorelease ausgleichen.) Als Ergebnis bleibt die tatsächliche + 1-Referenz, die von der ursprünglichen -copyWithZone: zurückgegeben wurde, dem Anrufer und der Anrufer erwartete eine +1 Referenz, Das ist alles gut.

Sie könnten ARC wahrscheinlich dazu bringen, dass Sie eine andere Methode aufrufen (die nicht effektiv durch Swizzling umbenannt werden würde), die eine + 1-Referenz zurückgibt. Wenn es das zurückgeben würde und da erwartet wird, dass die aktuelle Methode eine Referenz von +0 zurückgibt, würde sie es automatisch freigeben. Der Aufrufer würde es nicht beibehalten, da es eine +1-Referenz erwartet hat. Daher würde das Objekt vorzeitig freigegeben werden, was wahrscheinlich zu einem Absturz führen würde.