Utilisation de Super dans une catégorie d'objectif C?
-
05-07-2019 - |
Question
J'aimerais remplacer une méthode dans une classe Objective C dont je n'ai pas le source.
Je me suis penché sur la question et il semble que les catégories me permettent de le faire, mais j'aimerais utiliser le résultat de l'ancienne méthode dans ma nouvelle méthode, en utilisant super pour obtenir le résultat de l'ancienne méthode.
Cependant, chaque fois que j'essaie, ma méthode est appelée, mais "super" est nul ... Une idée pourquoi? Je développe actuellement un iPhone avec le SDK XCode 2.2. Je travaille certainement avec une instance d'une classe, et la méthode de la classe est une méthode d'instance.
@implementation SampleClass (filePathResolver)
-(NSString*) fullPathFromRelativePath:(NSString*) relPath
{
NSString *result = [super fullPathFromRelativePath: relPath];
... do some stuff with the old result
return result;
}
Note et clarification: D'après ce que je peux voir dans les documents Apple, il me semble que cela devrait être autorisé.
Documents de catégories sur developer.apple.com: Quand une catégorie substitue une méthode héritée, la méthode dans le catégorie peut, comme d'habitude, invoquer le implémentation héritée via un message À super. Cependant, si une catégorie remplace une méthode qui déjà existait dans la classe de la catégorie, il n'y a aucun moyen d'invoquer l'original mise en œuvre.
La solution
Les catégories étendent la classe d'origine, mais ne la sous-classent pas. Par conséquent, un appel à super
ne trouve pas la méthode.
Ce que vous voulez s'appelle Méthode Swizzling . Mais sachez que votre code pourrait casser quelque chose. Il existe un article sur Theocacao rédigé par Scot Stevenson à propos de Method Swizzling dans l'ancien environnement d'exécution Objective-C, Le cacao d'amour de Matt Gallagher contient un article sur Method Swizzling dans le nouvel objectif -C 2.0 runtime et un simple remplacement pour celui-ci.
Vous pouvez également sous-classer la classe, puis utiliser la sous-classe ou + (void) poseAsClass: (Class) aClass
pour remplacer la superclasse . Apple écrit:
Une méthode définie par une classe de pose peut, par un message à
super
, incorporer la méthode de la superclasse remplace.
Sachez qu'Apple a obsolète poseAsClass:
dans Mac OS X 10.5.
Autres conseils
Si vous souhaitez coder cette classe, renommez simplement le sélecteur en quelque chose que votre code peut utiliser et appelez le sélecteur d'origine à self
:
@implementation SampleClass (filePathResolver)
-(NSString*) myFullPathFromRelativePath:(NSString*) relPath
{
NSString *result = [self fullPathFromRelativePath: relPath];
... do some stuff with the old result
return result;
}
Si vous souhaitez remplacer l'implémentation par défaut de ce sélecteur pour cette classe, vous devez utiliser méthode swizzling approche.
Pas exactement dans la catégorie, mais il existe une solution de contournement en ajoutant la méthode de manière dynamique au moment de l'exécution. Samuel Défago, dans son article, décrit une manière élégante de créer une implémentation de bloc IMP appelant super, son article original se trouve ici
Le code approprié est:
#import <objc/runtime.h>
#import <objc/message.h>
const char *types = method_getTypeEncoding(class_getInstanceMethod(clazz, selector));
class_addMethod(clazz, selector, imp_implementationWithBlock(^(__unsafe_unretained id self, va_list argp) {
struct objc_super super = {
.receiver = self,
.super_class = class_getSuperclass(clazz)
};
id (*objc_msgSendSuper_typed)(struct objc_super *, SEL, va_list) = (void *)&objc_msgSendSuper;
return objc_msgSendSuper_typed(&super, selector, argp);
}), types);