-PerformSelector kullanma: yalnızca yöntemi çağırmaya kıyasla


Yanıtlar:


191

Temel olarak performSelector, verilen nesne üzerinde hangi seçicinin bir seçici çağıracağını dinamik olarak belirlemenize olanak tanır. Diğer bir deyişle, seçicinin çalışma zamanından önce belirlenmesine gerek yoktur.

Dolayısıyla, bunlar eşdeğer olsalar bile:

[anObject aMethod]; 
[anObject performSelector:@selector(aMethod)]; 

İkinci form bunu yapmanıza izin verir:

SEL aSelector = findTheAppropriateSelectorForTheCurrentSituation();
[anObject performSelector: aSelector];

mesajı göndermeden önce.


3
FindTheApp ProperSelectorForTheCurrentSituation () sonucunu aslında aSelector'a atayacağınıza ve ardından [anObject performSelector: aSelector] 'ı çağıracağınıza dikkat çekmek önemlidir. @selector bir SEL üretir.
Daniel Yankowsky

4
Kullanmak performSelector:, muhtemelen yalnızca sınıfınızda hedef eylemi uygularsanız yaptığınız bir şeydir. Kardeşler performSelectorInBackground:withObject:ve performSelectorOnMainThread:withObject:waitUntilDone:genellikle daha kullanışlıdır. Bir arka plan iş parçacığı oluşturmak ve sonuçları adı geçen arka plan iş parçacığından ana iş parçacığına geri çağırmak için.
PeyloW

2
performSelectorderleme uyarılarını bastırmak için de kullanışlıdır. Yöntemin var olduğunu biliyorsanız (kullandıktan sonra olduğu gibi respondsToSelector), Xcode'un "yanıt vermeyebilir" demesini durduracaktır your_selector. Sadece uyarının gerçek nedenini bulmak yerine onu kullanmayın . ;)
Marc

StackOverflow'daki başka bir başlıkta performSelector kullanımının korkunç bir tasarımın yansıması olduğunu ve tonlarca beğenildiğini okudum. Keşke tekrar bulabilsem. Google'da arama yaptım, sonuçları stackoverflow ile sınırlandırdım ve 18.000 sonuç aldım. Iyy.
Logicsaurus Rex

"korkunç bir tasarımın yansıması" aşırı derecede basittir. Bu, bloklar mevcut olmadan önce sahip olduğumuz şeydi ve o zaman veya şimdi tüm kullanımlar kötü değil. Her ne kadar şimdi bloklar o vardır mevcuttur, bu büyük olasılıkla çok basit bir şey yapıyorsun sürece yeni kod için daha iyi bir seçimdir.
Ethan

16

Sorudaki bu çok basit örnek için,

[object doSomething];
[object performSelector:@selector(doSomething)]; 

ne olacağı konusunda hiçbir fark yok. doSomething nesne tarafından eşzamanlı olarak yürütülecektir. Yalnızca "doSomething", hiçbir şey döndürmeyen ve herhangi bir parametre gerektirmeyen çok basit bir yöntemdir.

biraz daha karmaşık bir şey miydi, mesela:

(void)doSomethingWithMyAge:(NSUInteger)age;

işler karmaşıklaşır, çünkü [object doSomethingWithMyAge: 42];

parametrelere sahip tüm varyantlar yalnızca nesne parametrelerini kabul ettiğinden artık "performSelector" ın herhangi bir varyantıyla çağrılamaz.

Buradaki seçici "doSomethingWithMyAge:" olacaktır ancak

[object performSelector:@selector(doSomethingWithMyAge:) withObject:42];  

basitçe derlemez. 42 yerine bir NSNumber: @ (42) geçirmek de yardımcı olmaz, çünkü yöntem bir nesne değil temel bir C türü bekler.

Ek olarak, 2 parametreye kadar performSelector varyantları vardır, daha fazlası yoktur. Yöntemler birçok kez daha fazla parametreye sahipken.

PerformSelector'ın eşzamanlı varyantlarına rağmen:

- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;

her zaman bir nesneyi döndürürsem, basit bir BOOL veya NSUInteger da döndürebildim ve işe yaradı.

PerformSelector'ın iki ana kullanımından biri, önceki bir cevapta açıklandığı gibi, yürütmek istediğiniz yöntemin adını dinamik olarak oluşturmaktır. Örneğin

 SEL method = NSSelectorFromString([NSString stringWithFormat:@"doSomethingWithMy%@:", @"Age");
[object performSelector:method];

Diğer kullanım, daha sonra geçerli çalışma döngüsünde yürütülecek olan nesneye eşzamansız olarak bir mesaj göndermektir. Bunun için birkaç başka performSelector çeşidi vardır.

- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray *)modes;
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay;
- (void)performSelector:(SEL)aSelector target:(id)target argument:(id)arg order:(NSUInteger)order modes:(NSArray *)modes;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg;

(evet, bunları NSThread, NSRunLoop ve NSObject gibi birkaç Foundation sınıfı kategorisinden topladım)

Değişkenlerin her birinin kendine özgü bir davranışı vardır, ancak hepsi ortak bir şeyi paylaşır (en azından waitUntilDone NO olarak ayarlandığında). "PerformSelector" çağrısı hemen geri dönecek ve nesneye gönderilen mesaj sadece bir süre sonra geçerli çalışma döngüsüne konulacaktır.

Gecikmeli yürütme nedeniyle - doğal olarak seçicinin yönteminden hiçbir dönüş değeri mevcut değildir, bu nedenle tüm bu eşzamansız değişkenlerde - (geçersiz) dönüş değeri.

Umarım bunu bir şekilde halletmişimdir ...


12

@ennuikiller yerinde. Temel olarak, dinamik olarak oluşturulmuş seçiciler, kodu derlerken arayacağınız yöntemin adını bilmediğinizde (ve genellikle mümkün olamadığınızda) kullanışlıdır.

Önemli bir fark, -performSelector:arkadaşların ( çok iş parçacıklı ve gecikmeli varyantlar dahil ), 0-2 parametreli yöntemlerle kullanılmak üzere tasarlanmış olmaları nedeniyle bir şekilde sınırlı olmasıdır. Örneğin, -outlineView:toolTipForCell:rect:tableColumn:item:mouseLocation:6 parametre ile çağırmak ve geri döndürmek NSStringoldukça zahmetlidir ve sağlanan yöntemler tarafından desteklenmez.


5
Bunu yapmak için bir NSInvocationnesne kullanmanız gerekir .
Dave DeLong

6
Başka bir fark: performSelector:ve arkadaşların tümü nesne argümanları alır, yani onları aramak için kullanamazsınız (örneğin) setAlphaValue:, çünkü argümanı bir float'tır.
Chuck

4

Seçiciler, diğer dillerdeki işlev işaretçileri gibidir. Derleme zamanında çalışma zamanında hangi yöntemi çağırmak istediğinizi bilmediğinizde bunları kullanırsınız. Ayrıca, işlev işaretçileri gibi, çağrının yalnızca fiil kısmını kapsarlar. Yöntemin parametreleri varsa, bunları da iletmeniz gerekecektir.

An NSInvocation, daha fazla bilgiyi birbirine bağlamasının dışında benzer bir amaca hizmet eder. Sadece fiil kısmını değil, aynı zamanda hedef nesneyi ve parametreleri de içerir. Bu, şimdi değil gelecekte belirli parametrelere sahip belirli bir nesne üzerinde bir yöntem çağırmak istediğinizde kullanışlıdır. Bir uygun inşa edebilir NSInvocationve daha sonra ateşleyebilirsiniz.


5
Seçiciler, gerçekten bir işlev işaretçisi gibi değildir, çünkü bir işlev işaretçisi, bağımsız değişkenlerle çağırabileceğiniz bir şeydir ve bir seçici, onu uygulayan herhangi bir nesnede belirli bir yöntemi çağırmak için kullanılabilir; bir seçici, bir işlev işaretçisi gibi tam çağrı bağlamına sahip değildir.
bbum

1
Seçiciler işlev işaretçileriyle aynı değildir, ancak yine de benzer olduklarını düşünüyorum. Fiilleri temsil ederler. C işlevi işaretçileri aynı zamanda fiilleri de temsil eder. Ek bağlam olmadan hiçbiri yararlı değildir. Seçiciler bir nesne ve parametreler gerektirir; işlev işaretçileri parametreler gerektirir (bunlar üzerinde çalışılacak bir nesne içerebilir). Amacım, gerekli tüm içeriği içeren NSInvocation nesnelerinden ne kadar farklı olduklarını vurgulamaktı. Belki de karşılaştırmam kafa karıştırıcıydı, bu durumda özür dilerim.
Daniel Yankowsky

1
Seçiciler işlev işaretçisi değildir. Yakınında bile değil. Gerçekte, bir yöntemin "adını" içeren ("işlev" in aksine) basit C dizeleridir. Parametre türlerini yerleştirmedikleri için yöntem imzaları bile değildirler. Bir nesnenin aynı seçici için birden fazla yöntemi olabilir (farklı param türleri veya farklı dönüş türü).
Motti Shneor

-7

İkisi arasında ince bir fark daha var.

    [object doSomething]; // is executed right away

    [object performSelector:@selector(doSomething)]; // gets executed at the next runloop

İşte Apple Belgelerinden bir alıntı

"performSelector: withObject: afterDelay: Sonraki çalıştırma döngüsü döngüsü sırasında ve isteğe bağlı bir gecikme süresinden sonra geçerli iş parçacığı üzerinde belirtilen seçiciyi gerçekleştirir. Seçiciyi gerçekleştirmek için bir sonraki çalıştırma döngüsü döngüsüne kadar beklediğinden, bu yöntemler Şu anda yürütülen kod. Sıraya alınmış birden çok seçici, sıraya konuldukları sırayla birbiri ardına gerçekleştirilir. "


1
Cevabınız gerçeklere göre yanlış. Alıntı yaptığınız dokümanlar hakkındadır performSelector:withObject:afterDelay:, ancak soru ve pasajınızın kullandığı performSelector:, tamamen farklı bir yöntemdir. Dokümanlardan: <quote> performSelector:Yöntem, aSelectordoğrudan alıcıya bir mesaj göndermeye eşdeğerdir . </quote>
jscs

3
Açıklama için teşekkürler Josh. Haklısın; performSelector/performSelector:withObject/performSelector:withObject:afterDelayHepsinin aynı şekilde davrandığını sanıyordum ki bu bir hataydı.
avi
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.