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.