Ho due classi che possono fungere da delegate di una terza classe, ed entrambe implementano un protocollo formale fatto interamente di metodi opzionali. Una delle classi implementa tutto mentre un'altra implementa solo un paio di metodi che mi interessano. Tuttavia, in fase di esecuzione quando ho la seconda classe come delegato alla terza classe e la terza classe finisce per chiamare uno dei metodi facoltativi non implementati su quel delegato, ottengo un errore di runtime che dice essenzialmente "Target non risponde a questo selettore di messaggi. " Pensavo che l'obiettivo-c gestisse correttamente questo caso e che non avrebbe fatto nulla se quel metodo non fosse effettivamente definito sulla classe. Potrebbe esserci qualcosa che mi manca?Perché i metodi di protocollo opzionali non implementati causano errori di runtime quando tale metodo viene chiamato in obj-c?
risposta
Quando si chiama un metodo facoltativo del delegato, è necessario assicurarsi che risponde al selettore prima di chiamare:
if ([delegate respondsToSelector:@selector(optionalMethod)])
[delegate optionalMethod];
metodi Protocollo opzionale semplicemente significare l'oggetto che implementa il protocollo non deve implementare il metodo in questione - il callee quindi deve assolutamente verificare se l'oggetto implementa il metodo prima di chiamare (altrimenti si bloccherà, come notato). Queste categorie NSObject HOM possono essere utili:
@implementation NSObject (Extensions)
- (id)performSelectorIfResponds:(SEL)aSelector
{
if ([self respondsToSelector:aSelector]) {
return [self performSelector:aSelector];
}
return NULL;
}
- (id)performSelectorIfResponds:(SEL)aSelector withObject:(id)anObject
{
if ([self respondsToSelector:aSelector]) {
return [self performSelector:aSelector withObject:anObject];
}
return NULL;
}
@end
allora si può semplicemente fare:
[delegate performSelectorIfResponds:@selector(optionalMethod)];
buoni suggerimenti :) – Kevlar
........ Che cosa è HOM? – bandejapaisa
HOM = Messaggistica ordine superiore. –
blocchi potrebbe fornire una soluzione migliore. Essi consentono di eseguire condizionale di qualsiasi codice basato sull'esistenza di un'implementazione di un dato metodo:
-(void) performBlock:(void (^)(void))block ifRespondsTo:(SEL) aSelector{
if ([self respondsToSelector:aSelector]) {
block();
}
}
Utilizzando questa aggiunta alla NSObject, è possibile condizionale eseguire qualsiasi metodo @optional, indipendentemente dal numero di parametri che potrebbe avere .
Vedi How to safely send @optional protocol messages that might not be implemented
Questa soluzione blocchi funziona bene, una volta che si ottiene la testa avvolta attorno a ciò che sta succedendo. Ho aggiunto un risultato BOOL perché volevo essere in grado di eseguire condizionatamente uno dei numerosi metodi facoltativi. Alcuni suggerimenti se si sta tentando di implementare questa soluzione:
Innanzitutto, se non si sono ancora incontrate le estensioni/categorie, è sufficiente aggiungerla all'inizio della classe, FUORI dalla definizione della classe esistente. Sarà un'estensione pubblica o privata basata su dove la metti.
@implementation NSObject (Extensions)
// add block-based execution of optional protocol messages
-(BOOL) performBlock:(void (^)(void))block ifRespondsTo:(SEL) aSelector
{
if ([self respondsToSelector:aSelector]) {
block();
return YES;
}
return NO;
}
@end
In secondo luogo, ecco come si chiama dal codice:
BOOL b = [(NSObject*)self.delegate performBlock:^{
// code to run if the protocol method is implemented
}
ifRespondsTo:@selector(Param1:Param2:ParamN:)];
Sostituire Param1: Param2: paramN: con i nomi di ciascun parametro per il metodo di protocollo. Ognuno dovrebbe finire con due punti. Così, se il metodo di protocollo si presenta come:
-(void)dosomething:(id)blah withObj:(id)blah2 andWithObj(id)blah3;
l'ultima riga sarebbe simile a questa:
ifRespondsTo:@selector(dosomething:withObj:andWithObj:)];
- 1. Perché i metodi MonoBehaviour non sono implementati per l'override?
- 2. perché textFieldDidEndEditing: non viene chiamato?
- 3. Il protocollo GKLocalPlayerListener non viene chiamato
- 4. Protocollo ObjC Implementazione in Swift
- 5. Quando viene chiamato ServiceConnection.onServiceDisconnected()?
- 6. Trova metodi di classe non implementati
- 7. Reagire shouldComponentUpdate() viene chiamato anche quando puntelli o statale di tale componente non è cambiata
- 8. Quando viene chiamato il metodo IEnumerator.Reset()?
- 9. willTransitionToTraitCollection non viene chiamato, perché?
- 10. Quale metodo viene chiamato quando chiudo un'app
- 11. Perché il metodo della sottoclasse non viene chiamato?
- 12. Nuova parola chiave: perché il metodo derivato non viene chiamato?
- 13. Perché PostConstruct non viene chiamato?
- 14. Metodo onHandleIntent() non viene chiamato
- 15. ObjC: esiste un "protocollo di classe"?
- 16. Perché non viene chiamato onBackPressed()?
- 17. Perché il metodo toString() viene chiamato quando stampo un oggetto?
- 18. Cosa determina il processo in base al quale vengono risolti i metodi non implementati?
- 19. Candidato non è '@objc' ma il protocollo lo richiede
- 20. Esempi reali di metodi di protocollo @optional
- 21. Perché GetVaryByCustomString non viene chiamato
- 22. Come determinare quali metodi non sono implementati quando XCode ha avvertenze
- 23. risoluzione Metodo metodi di estensione con parametri opzionali
- 24. UICollectionReusableView non viene chiamato il metodo
- 25. Come vengono implementati i valori opzionali in Swift?
- 26. Quando viene chiamato il metodo layoutSubviews?
- 27. Objective C - Ricevi un avviso quando un metodo viene chiamato
- 28. NSFilePresenter -presentedSubitemDidAppearAtURL: il metodo non viene mai chiamato
- 29. Perché non viene chiamato -didDeselectRowAtIndexPath?
- 30. La metaClass di Groovy non riesce quando il metodo di overriding viene chiamato nel costruttore?
Lo sospettavo, ma speravo non avrei bisogno di aggiungere quelli se-controlla tutto il codice. Grazie per il puntatore. – Kevlar