Як я можу динамічно створити селектор під час виконання за допомогою 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.