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.

Était-ce utile?

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);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top