Yanıtlar:
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.
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.
performSelector
derleme 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 . ;)
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 ...
@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 NSString
oldukça zahmetlidir ve sağlanan yöntemler tarafından desteklenmez.
NSInvocation
nesne kullanmanız gerekir .
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.
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 NSInvocation
ve daha sonra ateşleyebilirsiniz.
İ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. "
performSelector:withObject:afterDelay:
, ancak soru ve pasajınızın kullandığı performSelector:
, tamamen farklı bir yöntemdir. Dokümanlardan: <quote> performSelector:
Yöntem, aSelector
doğrudan alıcıya bir mesaj göndermeye eşdeğerdir . </quote>
performSelector/performSelector:withObject/performSelector:withObject:afterDelay
Hepsinin aynı şekilde davrandığını sanıyordum ki bu bir hataydı.