Domanda

Vorrei sovrascrivere un metodo in una classe Obiettivo C a cui non ho la fonte.

L'ho esaminato e sembra che le Categorie dovrebbero permettermi di farlo, ma mi piacerebbe usare il risultato del vecchio metodo nel mio nuovo metodo, usando super per ottenere il risultato dei vecchi metodi.

Ogni volta che provo questo, il mio metodo viene chiamato, ma " super " è zero ... Qualche idea sul perché? Sto facendo lo sviluppo di iPhone con l'SDK XCode 2.2. Sto sicuramente lavorando con un'istanza di una classe e il metodo della classe è un metodo di istanza.

@implementation SampleClass (filePathResolver)
-(NSString*) fullPathFromRelativePath:(NSString*) relPath
{
    NSString *result = [super fullPathFromRelativePath: relPath];

  ... do some stuff with the old result

    return result;
}

Nota e chiarimenti: da quello che posso vedere in Apple Docs, mi sembra che questo dovrebbe essere permesso?

  

Documenti delle categorie su developer.apple.com:   Quando una categoria sovrascrive un metodo ereditato, il metodo in   la categoria può, come al solito, invocare il   implementazione ereditata tramite un messaggio   a super. Tuttavia, se una categoria   ignora un metodo che già   esisteva nella classe della categoria, lì   non è possibile invocare l'originale   implementazione.

È stato utile?

Soluzione

Le categorie estendono la classe originale, ma non la sottoclassano, quindi una chiamata a super non trova il metodo.

Quello che vuoi si chiama Metodo Swizzling . Ma tieni presente che il tuo codice potrebbe violare qualcosa. C'è un articolo su Theocacao scritto da Scot Stevenson sul metodo Swizzling nel vecchio runtime di Objective-C, Cocoa with Love di Matt Gallagher ha pubblicato un articolo su Method Swizzling nel nuovo Obiettivo -C 2.0 runtime e una semplice sostituzione per esso.

In alternativa, è possibile sottoclassare la classe e quindi utilizzare la sottoclasse o utilizzare + (void) poseAsClass: (Class) aClass per sostituire la superclasse . Apple scrive:

  

Un metodo definito da una classe in posa   può, tramite un messaggio a super ,   incorporare il metodo superclasse esso   sostituzioni.

Tieni presente che Apple ha deprecato poseAsClass: in Mac OS X 10.5.

Altri suggerimenti

Se esegui la codifica in base a questa classe, rinomina semplicemente il selettore in modo che il tuo codice possa utilizzare e chiama il selettore originale su self :

@implementation SampleClass (filePathResolver)
-(NSString*) myFullPathFromRelativePath:(NSString*) relPath
{
    NSString *result = [self fullPathFromRelativePath: relPath];

  ... do some stuff with the old result

    return result;
}

Se si desidera sovrascrivere l'implementazione predefinita di questo selettore per quella classe, è necessario utilizzare il metodo che sfreccia approccio.

Non esattamente nella categoria ma esiste una soluzione alternativa aggiungendo il metodo in modo dinamico in fase di esecuzione. Samuel D & # 233; fago nel suo articolo descrive un modo pulito per creare l'implementazione di blocchi IMP che chiama super, il suo articolo originale può essere trovato qui

Il codice pertinente è:

#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);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top