2012-12-26 4 views
6

Ho definito il mio protocollo. Ho menzionato due dei miei metodi di protocollo come facoltativi. Durante l'esecuzione, come posso sapere se il particolare metodo è opzionale o no? C'è un modo per scoprirlo?Come identificare un metodo di protocollo è opzionale durante il runtime?

+2

Perché questa informazione è necessaria in fase di esecuzione? (Solo curioso.) –

+1

@NikolaiRuhe Sì, +1 per quel commento. In generale, non dovremmo fare supposizioni ma testare le caratteristiche. I. e., Si dovrebbe testare per 'respondsToSelector:' invece di assumere che sia implementato un metodo obbligatorio. –

+0

Oppure puoi creare tu stesso un dizionario con tutti i nomi dei metodi come chiave e il suo valore come SÌ/NO per verificare se è richiesto o meno. –

risposta

12

Questo dovrebbe fare quello che vuoi:

BOOL MethodInProtocolIsRequired(Protocol *protocol, SEL methodSelector) 
{ 
    struct objc_method_description methodDesc = protocol_getMethodDescription(protocol, methodSelector, YES, YES); 
    return methodDesc.name != NULL; 
} 

Si noti che non sto commentando l'opportunità di utilizzare questo nel codice di spedizione, soprattutto perché non hai spiegato il motivo per cui vuoi farlo. Si noti inoltre che questa funzione restituirà NO quando viene fornito un selettore per un metodo che il protocollo non contiene. Questo è fondamentalmente ragionevole (dopotutto, se un protocollo non contiene un metodo, non è necessario!), Ma è possibile aggiungere sofisticazione alla funzione controllando se il protocollo contiene il metodo come metodo opzionale e restituisce qualcosa di diverso per tutti e tre gli scenari (richiesto, facoltativo, non-in-protocollo).

EDIT: programma di test semplice qui: https://gist.github.com/4381753

+0

Dovrei fare davvero questo invece del mio approccio complicato. +1. (Posso incorporare questo nella mia risposta?) –

+0

Ovviamente, e vedo che l'hai già fatto :). –

+0

sì, e ho fatto in modo di aggiungere l'attribuzione :) Questa volta sono io che dovrei avere RTFM ... -.- –

3

(non so la risposta al largo della parte superiore della mia testa. 1 minuto di googling mi ha aiutato.)

Si può fare questo usando la funzione protocol_copyMethodDescriptionList() che fa parte del runtime Objective-C libreria (libobjc). Il secondo argomento di questa funzione è un flag booleano che indica se sono richiesti i metodi da copiare nel protocollo. Quindi, se un metodo è nella lista restituita da questa funzione (chiamata usando gli argomenti appropriati), allora è un metodo obbligatorio.

SEL sctr = @selector(isThisMethod:requiredIn:theProtocol:); 

struct objc_method_description *methods; 
unsigned int nMethods; 
methods = protocol_copyMethodDescriptionList(
    objc_getProtocol("MyProtocolName"), // or @protocol(MyProtocolName) if you don't need this kind of dynamism 
    YES, // required? 
    YES, // instance method? (in general, protocols declare instance methods) 
    &nMethods 
); 

BOOL isRequired = NO; 
int i; 
SEL s; 
const char *sctrStr = sel_getName(sctr); 
for (i = 0; i < nMethods; i++) { 
    s = methods[i].name; 
    const char *sStr = sel_getName(s); 
    if (strcmp(sctrScr, sStr) == 0) { 
     isRequired = YES; 
     break; 
    } 
} 

free(methods); 

if (isRequired) { 
    // required 
} else { 
    // optional 
} 

Quindi, questo è possibile, ma è un po 'di un eccessivo, e come ho già detto nel mio commento alla tua domanda, non si dovrebbe verificare un metodo di essere opzionale o necessario, si dovrebbe verificare un istanza che risponde a un particolare selettore.

Modifica: sì, invece di copiare l'intero universo, avrei dovuto leggere più avanti nella documentazione. Come Andrew Madsen ha sottolineato, questo può essere ridotto a poche righe:

struct objc_method_description method; 
method = protocol_getMethodDescription(
    objc_getProtocol("MyProtocolName"), // or @protocol(MyProtocolName) 
    @selector(isThisSelector:required:) 
    YES, // required? 
    YES // instance method? 
); 

if (method.name != NULL) { 
    // required 
} else { 
    // optional 
} 
+1

Perché mai sulla Terra sarebbe cambiato il suo upvote a un downvote? –

+1

Se solo tu stavi usando GNU c booleans, puoi finalmente dire che hai risposto a una domanda-obiettivo senza alcun ObjC! (Estremamente tecnicamente però). – CodaFi

+1

@CodaFi: O C99 'bool' /' _Bool'. –

Problemi correlati