Jak mogę dynamicznie utworzyć selektor w czasie wykonywania z Objective-C?


93

Wiem, jak utworzyć plik SELw czasie kompilacji przy użyciu, @selector(MyMethodName:)ale chcę zrobić dynamiczne tworzenie selektora z pliku NSString. Czy to w ogóle możliwe?

Co mogę zrobić:

SEL selector = @selector(doWork:);
[myobj respondsToSelector:selector];

Co chcę zrobić: (pseudo kod, to oczywiście nie działa)

SEL selector = selectorFromString(@"doWork");
[myobj respondsToSelector:selector];

Szukałem dokumentacji Apple API, ale nie znalazłem sposobu, który nie opierałby się na @selector(myTarget:)składni czasu kompilacji .

Odpowiedzi:


180

Nie jestem programistą Objective-C, tylko sympatykiem, ale może NSSelectorFromString jest tym, czego potrzebujesz. W Runtime Reference wspomniano o jasności , że można go użyć do konwersji ciągu znaków na selektor.


5
Muszę odświeżyć moje Google-fu. to jest dokładnie to, czego szukałem (lub nie było).
Craigb

Cóż, nadal mam linki latające w moich zakładkach, odkąd przeczytałem dokumenty Objective-C 2.0 kilka dni temu.
Torsten Marek

40

Zgodnie z dokumentacją XCode, twój psuedocode w zasadzie robi to dobrze.

Najbardziej efektywne jest przypisywanie wartości do zmiennych SEL w czasie kompilacji za pomocą dyrektywy @selector (). Jednak w niektórych przypadkach program może potrzebować przekonwertować ciąg znaków na selektor w czasie wykonywania. Można to zrobić za pomocą funkcji NSSelectorFromString:

setWidthHeight = NSSelectorFromString(aBuffer);

Edycja: Bummer, zbyt wolno. : P


2
NSStringFromSelector(@"doWork")konwertuje to w drugą stronę (po prostu fyi)
bendytree

8
Myślę, że masz na myśli, NSStringFromSelector (@selector (doWork))
jpswain

A co podobno robi ten selektor? Nie powinniśmy określić bloku czy czegoś takiego?
user4951

13

Muszę powiedzieć, że jest to trochę bardziej skomplikowane, niż mogą sugerować odpowiedzi poprzednich respondentów ... jeśli naprawdę chcesz stworzyć selektor ... a nie tylko „zadzwoń do jednego”, który „masz w pobliżu” .. .

Musisz utworzyć wskaźnik funkcji, który będzie wywoływany przez twoją "nową" metodę. Więc dla metody takiej jak [self theMethod:(id)methodArg];, napiszesz ...

void (^impBlock)(id,id) = ^(id _self, id methodArg) { 
     [_self doSomethingWith:methodArg]; 
};

a następnie musisz wygenerować IMPblok dynamicznie, tym razem przechodząc, „self” SEL, i inne argumenty ...

void(*impFunct)(id, SEL, id) = (void*) imp_implementationWithBlock(impBlock);

i dodaj go do swojej klasy, wraz z dokładnym podpisem metody dla całego frajera (w tym przypadku "v@:@"void return, object caller, object argument)

 class_addMethod(self.class, @selector(theMethod:), (IMP)impFunct, "v@:@");

Możesz zobaczyć kilka dobrych przykładów tego rodzaju sztuczek środowiska uruchomieniowego w jednym z moich repozytoriów tutaj.


5

Wiem, że odpowiedź na to pytanie udzielono dawno temu, ale nadal chcę się nią podzielić. Można to zrobić sel_registerNamerównież za pomocą .

Przykładowy kod w pytaniu można przepisać w następujący sposób:

SEL selector = sel_registerName("doWork:");
[myobj respondsToSelector:selector];

2
Właściwie NSSelectorFromStringwspomniane przez @ torsten-marek używa sel_registerNamepod maską. appledev : "NSSelectorFromString przekazuje reprezentację znakową aSelectorName zakodowaną w UTF-8 do sel_registerName i zwraca wartość zwróconą przez tę funkcję"
PLG
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.