2011-11-06 14 views
7

in Objective C, i metodi di protocollo possono essere obbligatorie o facoltative:protocolli C Obiettivo che richiedono l'attuazione di almeno uno di un insieme di metodi

@protocol AProtocol 

@required 
-(void) aRequiredMethod; 

@optional 
-(void) anOptionalMethod; 

@end 

C'è un modo elegante per dire che l'oggetto conforme al protocollo deve rispondere ad almeno uno di un insieme di metodi, il mio sogno sarebbe qualcosa di simile

@protocol AProtocol 

@anyof 
-(void) onePossibleMethod; 
-(void) anotherPossibleMethod; 

@optional 
-(void) anOptionalMethod; 

@end 

EDIT:

Questo essere (per quanto ne so), impossibile, wou ld ci sia un modo per raccogliere un tempo di compilazione di avvertimento se una classe dichiarata conforme a un determinato protocollo fatto interamente di metodi opzionali

@protocol AProtocol 

@optional 
-(void) onePossibleMethod; 
-(void) anotherPossibleMethod; 

@end 

omesso di attuare almeno uno di loro.

+0

re: 'EDIT' non che ho visto. Se si vuole veramente automatizzare questo, è possibile utilizzare il runtime objc. – justin

risposta

3

Non c'è un ottimo modo per esprimere questo in Objective-C. Se si deve fare questo, IMO il modo più idiomatico e meno preoccupante del codice è qualcosa in questo senso:

@protocol AProtocol 

@required 
- (SEL)methodToUse; // returns one of "onePossibleMethod" or "anotherPossibleMethod" 

@optional 
-(void) onePossibleMethod; 
-(void) anotherPossibleMethod; 
-(void) anOptionalMethod; 

@en 
+0

Sono d'accordo che non esiste un ottimo modo, tuttavia mi piace la tua soluzione in quanto rende "ufficiale" (cioè diverso da commenti/documentazione) per gli sviluppatori che non hanno familiarità con il codice che sebbene i tre metodi siano opzionali, ti aspetti uno loro da implementare. – jbat100

0

È possibile avere una proprietà di delegato dinamica che consente solo l'assegnazione del delegato alle classi che implementano un metodo o l'altro, ma che sarebbe in fase di esecuzione e non in fase di compilazione. Potresti anche creare uno script bash che verificherebbe se uno o l'altro è stato implementato e sarebbe stato in fase di compilazione.

3

Bene, si sta lavorando con objC, quindi sarà necessario esercitare una certa moderazione da soli:

@protocol MONAbstractDataProvider 
@optional 
- (void)anOptionalMethod; 
@end 

@protocol MONDataProviderA <MONAbstractProvider> 
@required 
- (void)onePossibleMethod; 
@end 

@protocol MONDataProviderB <MONAbstractProvider> 
@required 
- (void)anotherPossibleMethod; 
@end 

In questo caso, dovrete fare un test confromsToProtocol: al callsite, piuttosto che respondsToSelector: prova per onePossibleMethod e anotherPossibleMethod. Quindi si passa MONAbstractDataProvider in giro. Questo può introdurre qualche tipo di sicurezza, purché si ricordino le regole, ma in realtà è solo leggermente migliore rispetto all'approccio tradizionale.

Così il lato client sarebbe simile a questa:

- (void)update:(NSObject<MONAbstractDataProvider>*)provider 
{ 
    if ([provider conformsToProtocol:@protocol(MONDataProviderA)]) { 
     [(NSObject<MONDataProviderA>*)protocol onePossibleMethod]; 
    } 
    else if ([provider conformsToProtocol:@protocol(MONDataProviderB)]) { 
     [(NSObject<MONDataProviderB>*)provider anotherPossibleMethod]; 
    } 
    else { 
     assert(0 && "rule broken"); 
    } 
} 

Che ovviamente presuppone che il client conosce tutti i derivati.

Si può invece preferisce l'approccio singolare semplice se entrambi sono void:

@protocol MONAbstractDataProvider 
@required 
- (void)performPossibleMethod; 
@optional 
- (void)anOptionalMethod; 
@end 
+0

grazie per la tua risposta dettagliata, questo sarebbe un modo per eseguire il controllo in fase di esecuzione. Idealmente, ciò che vorrei è una sorta di controllo in fase di compilazione che sollevi un avvertimento (ho modificato leggermente la domanda). – jbat100

+0

@ jbat100 hmm - non ho reso molto chiaro il dettaglio dell'approccio. il controllo del tempo di compilazione entra perché "MONAbstractDataProvider' viene adottato solo * indirettamente *. le classi dovrebbero solo adottare "MONDataProviderA" o "MONDataProviderB", mai "MONAbstractDataProvider" direttamente. – justin

Problemi correlati