6

Intento descubrir cómo funcionan realmente las cosas. Así que pensé que cuando sobrescribiera ciertos métodos usando categorías, obtendría NSLogs interesantes.Cómo llamar a la implementación original cuando sobrescribe un método con una categoría?

@implementation UIView(Learning) 
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { 
    NSLog(@"-hitTest:withEvent: event=%@", event); 
    return [self hitTest:point withEvent:event]; 
} 
@end 

super y self no funcionan aquí. ¿Hay alguna manera de llamar a la implementación original de -hitTest: withEvent :? Lo que quiero es un NSLog cada vez -hitTest: withEvent: se llama en un UIView.

Es solo para fines de aprendizaje personal. Quiero ver la entrega del evento en acción.

+0

Súper no funciona en una categoría porque' No lo estoy llamando en la misma clase, lo estás llamando en el super de clase. Entonces, en este caso, el super es un UIResponder que no tiene un método hitTest: withEvent. Llamar a uno solo da como resultado un bucle infinito porque está anulando hitTest: withEvent para "self". –

+0

Mi comentario parece un poco fuera de lugar aquí, pero tenía sentido antes de que el comentario anterior borrara el suyo. –

Respuesta

14

Puede hacerlo, pero no el uso de una categoría. Una categoría reemplaza a un método. (Advertencia, analogía con el automóvil) Si tiene un automóvil, lo destruye y lo reemplaza con un automóvil nuevo, ¿puede seguir usando el automóvil viejo? No, porque ya no existe y ya no existe. Lo mismo con las categorías.

Lo que podría hacer es usar el tiempo de ejecución de Objective-C para añadir el método con un nombre diferente en tiempo de ejecución (por ejemplo, "bogusHitTest:withEvent:"), a continuación, cambiar las implementaciones de hitTest:withEvent: y bogusHitTest:withEvent:. De esta forma, cuando el código llame al hitTest:withEvent:, ejecutará el código originalmente escrito para bogusHitTest:withEvent:. A continuación, puede hacer que ese código invoque bogusHitTest:withEvent:, que ejecutará la implementación original.

lo tanto, el método de falsa se vería así:

- (UIView *) bogusHitTest:(CGPoint)point withEvent:(UIEvent *)event { 
    NSLog(@"executing: %@", NSStringFromSelector(_cmd)); 
    return [self bogusHitTest:point withEvent:event]; 
} 

El código para intercambiar los métodos sería algo a lo largo de las líneas de:

Method bogusHitTest = class_getInstanceMethod([UIView class], @selector(bogusHitTest:withEvent:)); 
Method hitTest = class_getInstanceMethod([UIView class], @selector(hitTest:withEvent:)); 
method_exchangeImplementations(bogusHitTest, hitTest); 
+0

Genial. Corto. Trabajos. ¡Gracias! –

0

Desafortunadamente, no, no hay forma de invocar la implementación original de un método que anula. Una vez que lo implemente en la categoría, habrá eliminado el método original.

Enviando el mismo mensaje al super debería funcionar en su método; llamará al método en la superclase como normal (si hay uno).

Enviando el mismo mensaje al self creará un bucle infinito, como estoy seguro que ha descubierto.

+1

Como dijo Adam, esto no es posible de esta manera, pero podrías echarle un vistazo a Method Swizzling. Hay un gran ejemplo aquí: http://github.com/marksands/UITextViewLinkOptions –

3

Lo que se quiere hacer es llamado método swizzling: http://www.cocoadev.com/index.pl?MethodSwizzling

+0

No estoy seguro, pero el artículo parece estar un poco desactualizado. Dave DeLong publicó una solución que funciona bastante bien con mucho menos código. Gracias de todos modos :-) –

+0

@BugAlert para que sepan, mi código * es * método swizzling. El artículo vinculado solo tiene mucha más información al respecto. :) –

Cuestiones relacionadas