2013-05-21 9 views
17

In una sottoclasse, sto sovrascrivendo un metodo che non è esposto nella super classe. So di avere la firma corretta poiché sta sovrascrivendo con successo l'implementazione della superclasse. Tuttavia, come parte della nuova implementazione, ho bisogno di chiamare l'implementazione della superclasse dall'implementazione della sottoclasse.Accesso a un metodo in una super classe quando non è esposto

perché non è esposta devo richiamare il metodo tramite una chiamata a performSelector:

SEL superClassSelector = NSSelectorFromString(@"methodToInvoke"); 
[super performSelector:superClassSelector]; 

Tuttavia, nella mia applicazione questo si traduce in un ciclo ricorsivo infinito in cui l'implementazione del sottoclasse viene richiamato ogni volta che provo a invocare l'implementazione della superclasse.

Qualche idea?

Mi rendo conto che questa è una situazione atipica, ma sfortunatamente non c'è modo di aggirare ciò che sto cercando di fare.

risposta

44

Il modo in cui mi sono occupato è di ripetere la tua interfaccia di super-classe nel tuo file di implementazione della sottoclasse con il metodo che vuoi chiamare dalla sottoclasse

@interface MySuperclass() 
- (void)superMethodIWantToCall; 
@end 

@implementation MySubclass 


- (void)whateverFunction { 
    //now call super method here 
    [super superMethodIWantToCall]; 
} 

@end 

Non sono sicuro se questo è il modo migliore per fare le cose ma è semplice e funziona per me!

+0

Questo è esattamente l'approccio corretto. In molti casi lo fai con una categoria piuttosto che con un'estensione (usando '(Superclasse)' piuttosto che '()' nell'interfaccia), ma in ogni caso è l'approccio più sicuro e più pulito. –

+0

È fantastico. Assolutamente geniale ... grazie! –

+0

Neat. Soprattutto funziona bene per passare attraverso i metodi delegate, basta riformulare il protocollo: '@interface UIScrollView() ' –

2

Un modo per andare è quello di creare una categoria della classe in un file separato con il metodo che si sta cercando di esporre

@interface MyClass (ProtectedMethods) 

- (void)myMethod; 

@end 

e sul .m

@implementation MyClass (ProtectedMethods) 

- (void)myMethod { 

} 

@end 

Poi, import questa categoria dai tuoi file .m, e sei a posto. Non è la cosa più bella, ma farà il trucco

+0

Questo è in gran parte lo stesso della risposta accettata, con l'importante differenza che non si deve _ definire il metodo (nessuna sezione '@ implementation '), o si può benissimo clobare l'implementazione esistente che si sta tentando di chiamare. Nella migliore delle ipotesi, non sarà definito quale implementazione venga utilizzata. –

+0

Non lo è, perché in questo modo si garantisce che sia la super che la sottoclasse fanno riferimento allo "stesso metodo". Supponi che qualcuno debba cambiare la tua superclasse e cambiare il nome del metodo o aggiungervi un parametro, come farà a sapere che hai una sottoclasse da qualche parte che ridefinisce il metodo? avrai un incidente. Dipende davvero dal tipo di progetto e da quanti sviluppatori stai lavorando. Di norma, penso che non sia mai bello ridefinire qualcosa che è già definito altrove – Ismael

+0

Mentre leggo la tua risposta, questo è esattamente ciò che stai sostenendo: ridefinire il 'myMethod' che è già definito nella superclasse. –

9

Questo non funziona perché si invia solo performSelector:, non il selettore che si passa a quello, alla superclasse. performSelector: continua a cercare il metodo nell'elenco dei metodi della classe corrente. Quindi, si finisce con la stessa implementazione di sottoclasse.

Il modo più semplice per farlo potrebbe essere quello di scrivere solo nella vostra chiamata a objc_msgSendSuper():

// Top level (this struct isn't exposed in the runtime header for some reason) 
struct objc_super 
{ 
    id __unsafe_unretained reciever; 
    Class __unsafe_unretained superklass; 
}; 

// In the subclass's method 
struct objc_super sup = {self, [self superclass]}; 
objc_msgSendSuper(&sup, _cmd, other, args, go, here); 

Questo può causare problemi nel caso generale, come Rob Napier ha sottolineato di seguito. Ho suggerito questo in base al presupposto che il metodo non ha alcun valore di ritorno.

+0

+1 questo è corretto ... ho trascurato che, cancellata la mia risposta –

+0

Non penso che dovrebbe ... –

+2

In generale dovresti non chiamare 'objc_msgSend *' a meno che non ci sia una ragione molto forte per farlo. Il codice sopra può crash o avere un comportamento mal definito a seconda del tipo esatto di ritorno del metodo e del processore che si sta eseguendo avanti. (Potrebbe essere necessario chiamare 'objc_msgSendSuper_fpret()' ad esempio per alcuni metodi.) @ La risposta di ModernCarpentry è il modo più semplice e corretto per farlo. –

Problemi correlati