it-swarm.com.ru

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

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

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

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

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

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

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

92
craigb

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

180
Torsten Marek

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

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

setWidthHeight = NSSelectorFromString(aBuffer);

Правка: облом, слишком медленно. :П

40
Josh Gagnon

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

Вам нужно создать указатель на функцию, который будет вызываться вашим "новым" методом .. поэтому для такого метода, как [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);

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

 class_addMethod(self.class, @selector(theMethod:), (IMP)impFunct, "[email protected]:@");

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

11
Alex Gray

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

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

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