Как я могу динамически создать селектор во время выполнения с Objective-C? - PullRequest
92 голосов
/ 22 сентября 2008

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

Что я могу сделать:

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

Что я хочу сделать: (псевдокод, это, очевидно, не работает)

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

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

Ответы [ 4 ]

180 голосов
/ 22 сентября 2008

Я не программист Objective-C, просто сочувствующий, но, возможно, NSSelectorFromString - это то, что вам нужно. В Справочнике по времени выполнения упомянуто, что вы можете использовать его для преобразования строки в селектор.

40 голосов
/ 22 сентября 2008

Согласно документации XCode, ваш psuedocode в основном понимает все правильно.

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

setWidthHeight = NSSelectorFromString(aBuffer);

Редактировать: Облом, слишком медленно. : Р

11 голосов
/ 01 февраля 2014

Я бы сказал, что это немного сложнее , чем могли бы предположить ответы предыдущих респондентов ... если вы действительно действительно хотите создать селектор ... не просто "позвони одному", которого ты "лежишь" ...

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

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

и затем вам нужно сгенерировать блок IMP динамически, на этот раз, передавая "self", SEL и любые аргументы ...

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

и добавьте его в свой класс вместе с точной сигнатурой метода для всей присоски (в данном случае "v@:@", возврат void, вызывающий объект, аргумент объекта)

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

Вы можете увидеть некоторые хорошие примеры такого рода shenanigans во время выполнения , в одном из моих репозиториев, здесь.

4 голосов
/ 26 февраля 2014

Я знаю, что на это уже давно дан ответ, но все же хочу поделиться. Это можно сделать с помощью sel_registerName.

Пример кода в вопросе можно переписать так:

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