2012-12-26 11 views
6

Mam zdefiniowany mój protokół. Wspomniałem dwie z moich metod protokołów jako opcjonalne. W trakcie wykonywania, jak mogę dowiedzieć się, czy dana metoda jest opcjonalna czy nie? Czy jest jakiś sposób, aby się tego dowiedzieć?Jak zidentyfikować metodę protokołu jest opcjonalna w czasie wykonywania?

+2

Dlaczego ta informacja jest potrzebna w czasie wykonywania? (Po prostu ciekawy.) –

+1

@NikolaiRuhe Yep, +1 za ten komentarz. Ogólnie rzecz biorąc, nie powinniśmy przyjmować założeń, ale testować funkcje. I. e., Należy testować dla 'responsesToSelector:' zamiast zakładać, że zaimplementowana jest wymagana metoda. –

+0

Możesz też sam sporządzić słownik ze wszystkimi nazwami metod jako kluczem i jego wartością TAK/NIE, aby sprawdzić, czy jest wymagany, czy nie. –

Odpowiedz

12

to powinien robić to, co chcesz:

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

Zauważ, że ja nie komentuje celowości stosowania tego w kodzie wysyłki, zwłaszcza, że ​​nie wyjaśniłeś, dlaczego chcesz to zrobić. Zwróć też uwagę, że funkcja ta zwróci wartość NO, gdy zostanie podany selektor dla metody, której protokół nie zawiera. Jest to zasadniczo uzasadnione (w końcu, jeśli protokół nie zawiera metody, nie jest wymagane!), Ale można dodać wyrafinowanie do funkcji, sprawdzając, czy protokół zawiera metodę jako metodę opcjonalną i zwraca coś innego dla wszystkie trzy scenariusze (wymagane, opcjonalne, nie w protokole).

EDIT: Prosty program testowy tutaj: https://gist.github.com/4381753

+0

Naprawdę powinienem to robić zamiast mojego skomplikowanego podejścia. +1. (Czy mogę uwzględnić to w mojej odpowiedzi?) –

+0

Oczywiście, i widzę, że już to zrobiłeś :). –

+0

Tak, i upewniłem się, że dodam atrybucję :) Tym razem to ja powinienem mieć RTFM ... -.- –

3

(ja nie znam odpowiedzi off na szczycie głowy. 1 minuty od googlowania mi pomógł.)

Można to zrobić za pomocą funkcji protocol_copyMethodDescriptionList() która jest częścią Objective-C starcie biblioteka (libobjc). Drugi argument tej funkcji jest flagą typu Boolean, która wskazuje, czy wymagane są metody, które mają być skopiowane w protokole. Tak więc, jeśli metoda znajduje się na liście zwróconej przez tę funkcję (wywołanej za pomocą odpowiednich argumentów), jest to wymagana metoda.

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 
} 

Tak, to jest możliwe, ale to trochę overkill, i jak już wspomniałem w moim komentarzu na swoje pytanie, nie należy testować metoda jest opcjonalne lub wymagane, należy przetestować za instancja odpowiadająca na określony selektor.

Edytuj: tak, zamiast kopiować cały wszechświat, powinienem przeczytać frazę w dokumentacji. Jak Andrew Madsen zauważył, to można sprowadzić do kilku linii:

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

Dlaczego, na Boga, zmieniłby się ktoś, kto stał się jego przegranym? –

+1

Gdybyście tylko używali GNU c booleans, moglibyście w końcu powiedzieć, że odpowiedzieliście na pytania-c bez żadnych ObjC! (Niezwykle technicznie jednak). – CodaFi

+1

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

Powiązane problemy