Objective-C ile çalışma zamanında dinamik olarak nasıl seçici oluşturabilirim?


93

SELKullanarak bir derleme zamanında nasıl oluşturulacağını biliyorum @selector(MyMethodName:)ama yapmak istediğim şey dinamik olarak bir NSString. Bu mümkün mü?

Ne yapabilirim:

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

Yapmak istediğim şey: (sözde kod, bu kesinlikle çalışmıyor)

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

Apple API belgelerini araştırıyordum, ancak derleme zamanı @selector(myTarget:)sözdizimine dayanmayan bir yol bulamadım .

Yanıtlar:


180

Ben bir Objective-C programcısı değilim, sadece bir sempatizan değilim, ama belki NSSelectorFromString ihtiyacınız olan şeydir. Çalışma Zamanı Başvurusunda , bir dizeyi seçiciye dönüştürmek için kullanabileceğiniz açık bir şekilde belirtilmiştir .


5
Google-fu'umu tazelemem gerekiyor. tam olarak aradığım (ya da olmadığım) buydu.
craigb

Birkaç gün önce Objective-C 2.0 belgelerini okuduğumdan beri yer imlerimde hala bağlantılar vardı.
Torsten Marek

40

XCode belgelerine göre, psuedocode'unuz temelde doğru anlıyor.

@Selector () direktifiyle derleme sırasında SEL değişkenlerine değer atamak en verimli yöntemdir. Bununla birlikte, bazı durumlarda, bir programın çalışma zamanında bir karakter dizesini bir seçiciye dönüştürmesi gerekebilir. Bu, NSSelectorFromString işleviyle yapılabilir:

setWidthHeight = NSSelectorFromString(aBuffer);

Düzenleme: Serseri, çok yavaş. : P


2
NSStringFromSelector(@"doWork")dönüştürür diğer yolu (sadece Bilginize)
bendytree

8
Sanırım NSStringFromSelector (@selector (doWork))
jpswain

Ve bu seçici sözde ne yapıyor? Bir blok falan belirtmemiz gerekmez mi?
user4951

13

Önceki yanıtlayanların yanıtlarının önerebileceğinden biraz daha karmaşık olduğunu söylemeliyim ... eğer gerçekten bir seçici oluşturmak istiyorsanız ... sadece "etrafta yattığınız" "birini arayın" değil .. .

"Yeni" yönteminiz tarafından çağrılacak bir işlev işaretçisi oluşturmanız gerekir .. yani bir yöntem için şunu [self theMethod:(id)methodArg];yazarsınız ...

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

ve sonra IMPbloğu dinamik olarak oluşturmanız gerekir , bu sefer, geçen, "öz" SEL, ve herhangi bir argüman ...

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

ve tüm enayi için doğru bir yöntem imzasıyla birlikte sınıfınıza ekleyin (bu durumda "v@:@", void dönüşü, nesne çağırıcısı, nesne argümanı)

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

Bu tür çalışma zamanı saçmalıklarının bazı güzel örneklerini burada depolarımdan birinde görebilirsiniz.


5

Bunun uzun zaman önce yanıtlandığını biliyorum ama yine de paylaşmak istiyorum. Bu da kullanılarak yapılabilir sel_registerName.

Sorudaki örnek kod şu şekilde yeniden yazılabilir:

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

2
Aslında NSSelectorFromString@ torsten-marek'in bahsettiği sel_registerNamebaşlık altında kullanır . appledev : "NSSelectorFromString, aSelectorName'in UTF-8 ile kodlanmış karakter temsilini sel_registerName'e iletir ve bu işlev tarafından döndürülen değeri döndürür"
PLG
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.