2016-06-12 17 views
3

Ich muss aus der Kategorie eine konkrete Implementierung der Methode aufrufen (auch wenn sie überschrieben wird). Ist es möglich? (Nur für den Fall: Ich weiß, alle Methoden in Objective-C sind virtuelle.)Nicht-virtuelle Methoden in Objective-C

// class A 
@interface A 

- (void)foo; 

@end 

@implementation A 

- (void)foo 
{ 
    NSLog(@"initial foo"); 
} 

@end 

// subclass of A 
@interface A1: A 

@end 

@implementation A1 

- (void)foo 
{ 
    NSLog(@"overridden foo"); 
} 

@end 

// category to A 
@interface A (Category) 

- (void)bar; 

@end 

@impletemtation A (Category) 

- (void)bar 
{ 
    [self foo]; // probably, I should specify here what exactly must be self 
        // but I don't know how 
} 

@end 

///////////////////////////////////////////////////////////////// 
A1 *a = [[A1 alloc] init]; 

[a bar]; // now the "overridden foo" string will be printed 
      // my goal is to print "initial foo" !!! 
+3

Wollen Sie wirklich Verkapselung so brechen? – Sulthan

+0

Ich bin mir noch nicht sicher. Trotzdem bin ich neugierig zu wissen, ob das theoretisch möglich ist. –

+0

Das wäre ein riesiger Code-Geruch, aber hast du '[super foo];'? – vikingosegundo

Antwort

3

Of Natürlich musst du nichts ändern.

Sie können einen Funktionszeiger auf die Durchführung jeder Methode auf einer bestimmten Klasse erhalten:

A* receiver = … 
IMP impOnA = class_getMethodImplementation([A class], @selector(foo)); 
((void (*)(id, SEL))impOnA)(receiver, @selector(foo)); // or whatever signature 
+0

Wäre nett, wenn Sie die Antwort leicht aktualisieren. Der Compiler erlaubt es nicht, impOnA als Funktionsnamen mit mehreren Parametern zu verwenden, Sie müssen es in ** void (* imp) (id, SEL) ** umwandeln. Vielen Dank, es ist eine elegante Lösung. –

+0

Natürlich sind Sie richtig. Man muss den Funktionszeiger werfen. (Sorry, in Safari eingegeben.) Ich habe es hinzugefügt. –

+0

Oh, ich bin aus der Ukraine. Lass uns heute Abend ein gutes Spiel machen - und einen deutschen Sieg. ;-) –

-1

Dieses Ihr Problem lösen kann:

// class A 
@interface A 

- (void)foo; 

@end 

@implementation A 

- (void)foo 
{ 
    [self fooImpl]; 
} 

- (void)fooImpl 
{ 
    NSLog(@"initial foo"); 
} 

@end 

// subclass of A 
@interface A1: A 

@end 

@implementation A1 

- (void)foo 
{ 
    NSLog(@"overridden foo"); 
} 

@end 

// category to A 
@interface A (Category) 

- (void)bar; 

@end 

@impletemtation A (Category) 

- (void)bar 
{ 
    [self fooImpl]; // probably, I should specify here what exactly must be self 
        // but I don't know how 
} 

@end 

///////////////////////////////////////////////////////////////// 
A1 *a = [[A1 alloc] init]; 

[a bar]; // now the "overridden foo" string will be printed 
      // my goal is to print "initial foo" !!! 
+0

Leider kann ich das nicht tun. In meinem Fall ist A UIViewController und ich kann seine Implementierung nicht umschreiben. –

0

schließlich. in der Tat Methode swizzing

@implementation A (Category) 

- (void)quux 
{ 
    NSLog(@"quux"); 
} 

- (void)bar 
{ 
    Class class = [A class]; 

    SEL originalSelector = @selector(foo); 
    SEL swizzledSelector = @selector(quux); 

    Method originalMethod = class_getInstanceMethod(class, originalSelector); 
    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector); 

    method_exchangeImplementations(originalMethod, swizzledMethod); 
    [self quux]; 
    method_exchangeImplementations(originalMethod, swizzledMethod); 
} 

@end 
+0

Vielen Dank für die Absicht, aber es löst das Problem nicht. Hier ersetzen Sie die Implementierung vorübergehend, aber ich brauche sie nicht. Alles was ich brauche ist die Methode foo aus der Klasse A anzurufen. –

2

funktioniert können Sie Matt Gallagher's supersequent implementation approach passen die spezifische Methode zu finden, die Sie aufrufen möchten.

Alternativ können Sie nur die Klasse gesetzt vorübergehend:

Class realClass = object_getClass(self); 
Class fakeClass = [A class]; 

object_setClass(self, fakeClass); 
[self foo]; 
object_setClass(self, realClass); 

(. Ich bin auf meinem Handy, also nicht 100% sicher über die Syntax, aber die Idee funktionieren soll)

+0

Er möchte eine bestimmte Implementierung auswählen, nicht die Klasse eines Objekts ändern. Dies kann der Implementierung von "foo" schaden. –

+1

Welche Art von Schaden meinen Sie konkret? –