Comment appeler la mise en œuvre d'origine si vous écrasez une méthode avec une catégorie?
-
28-09-2019 - |
Question
J'essaie de comprendre comment les choses fonctionnent vraiment. Donc, je pensais quand je remplacer certaines méthodes en utilisant les catégories, je recevrais NSLogs intéressantes.
@implementation UIView(Learning)
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
NSLog(@"-hitTest:withEvent: event=%@", event);
return [self hitTest:point withEvent:event];
}
@end
super et l'auto ne fonctionne pas ici. Est-il possible d'appeler la mise en œuvre originale de -hitTest: withEvent :? Ce que je veux est un NSLog chaque fois -hitTest: withEvent:. Est appelée sur un UIView
Il est juste à des fins d'apprentissage personnel. Je veux voir le cas dans l'action.
La solution
Vous pouvez le faire, mais pas en utilisant une catégorie. Une catégorie remplace une autre méthode. (Attention, l'analogie de voiture) Si vous avez une voiture, et vous détruire cette voiture et le remplacer par une nouvelle voiture, vous pouvez toujours utiliser la vieille voiture? Non, car il est parti et n'existe plus. La même chose avec les catégories.
Ce que vous pouvez faire est d'utiliser le moteur d'exécution Objective-C pour ajouter la méthode sous un autre nom à l'exécution (par exemple, « bogusHitTest:withEvent:
»), puis échanger les implémentations de hitTest:withEvent:
et bogusHitTest:withEvent:
. De cette façon, lorsque les appels de code hitTest:withEvent:
, il va exécuter le code qui a été initialement écrit pour bogusHitTest:withEvent:
. Vous pouvez alors ce code Invoke bogusHitTest:withEvent:
, qui exécutera la mise en œuvre originale.
Ainsi, la méthode bogus ressemblerait à ceci:
- (UIView *) bogusHitTest:(CGPoint)point withEvent:(UIEvent *)event {
NSLog(@"executing: %@", NSStringFromSelector(_cmd));
return [self bogusHitTest:point withEvent:event];
}
Le code pour échanger les méthodes serait quelque chose le long des lignes de:
Method bogusHitTest = class_getInstanceMethod([UIView class], @selector(bogusHitTest:withEvent:));
Method hitTest = class_getInstanceMethod([UIView class], @selector(hitTest:withEvent:));
method_exchangeImplementations(bogusHitTest, hitTest);
Autres conseils
Qu'est-ce que vous voulez faire est appelée méthode swizzling: http://www.cocoadev.com/ index.pl?MethodSwizzling
Malheureusement, non, il n'y a aucun moyen d'appeler la mise en œuvre originale d'une méthode que vous substituez. Une fois que vous implémentez dans la catégorie que vous avez éliminé la méthode originale.
L'envoi du même message à super
devrait fonctionner dans votre méthode; il va appeler la méthode de la superclasse normalement (si elle existe).
L'envoi du même message à self
va créer une boucle infinie, comme je suis sûr que vous avez découvert.