Як я можу динамічно створити селектор під час виконання за допомогою Objective-C?


93

Я знаю, як створити час SELкомпіляції, використовуючи, @selector(MyMethodName:)але те, що я хочу зробити, це створити селектор динамічно з NSString. Чи можливо це взагалі?

Що я можу зробити:

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

Що я хочу зробити: (псевдо-код, очевидно, це не працює)

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

Я шукав документи Apple API, але не знайшов способу, який би не покладався на @selector(myTarget:)синтаксис часу компіляції .

Відповіді:


180

Я не програміст Objective-C, просто прихильник, але, можливо, NSSelectorFromString - це те, що вам потрібно. У посиланні під час виконання згадується чіткість, за допомогою якої ви можете перетворити рядок на селектор.


5
Мені потрібно придумати свій Google-фу. це саме те, що я шукав (або не був таким, яким може бути).
craigb

Ну, у мене все ще були посилання, які летіли у моїх закладках, оскільки я кілька днів тому прочитав документи Objective-C 2.0.
Торстен Марек

40

Згідно з документацією XCode, ваш psuedocode, в основному, правильно відповідає.

Найбільш ефективно призначати значення змінним SEL під час компіляції за допомогою директиви @selector (). Однак у деяких випадках програмі може знадобитися перетворити символьну рядок у селектор під час виконання. Це можна зробити за допомогою функції NSSelectorFromString:

setWidthHeight = NSSelectorFromString(aBuffer);

Редагувати: облом, занадто повільно. : P


2
NSStringFromSelector(@"doWork")перетворює це в інший спосіб (просто fyi)
bendytree

8
Я думаю, ви маєте на увазі, NSStringFromSelector (@selector (doWork))
jpswain

І що нібито робить цей селектор? Чи не слід вказати блок чи щось інше?
user4951

12

Потрібно сказати, що це трохи складніше, ніж відповіді попередніх респондентів ... якщо ви дійсно хочете створити селектор ... а не просто "зателефонувати одному", якого ви "розкладаєте" .. .

Вам потрібно створити покажчик функції, який буде викликаний вашим "новим" методом .. так що для такого методу, як [self theMethod:(id)methodArg];, ви б написали ...

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

а потім вам потрібно IMPдинамічно генерувати блок, на цей раз, передаючи "self", the SELта будь-які аргументи ...

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

і додайте його до свого класу разом із точним підписом методу для цілого присоски (у цьому випадку "v@:@"повернення void, виклик об'єкта, аргумент об'єкта)

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

Ви можете побачити декілька хороших прикладів такого роду тривожних махінацій в одному з моїх репозитаріїв тут.


5

Я знаю, що на це вже давно відповідали, але все ж хочу поділитися. Це можна зробити за допомогоюsel_registerName .

Приклад коду у питанні можна переписати так:

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

2
Власне, NSSelectorFromStringзгаданий @ torsten-marek використовує sel_registerNameпід капотом. appledev : "NSSelectorFromString передає представлене символом aSelectorName кодоване UTF-8 значення sel_registerName і повертає значення, повернене цією функцією"
PLG
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.