Jawaban:
Pada dasarnya performSelector memungkinkan Anda menentukan secara dinamis selektor mana yang akan dipanggil selektor pada objek tertentu. Dengan kata lain, pemilih tidak perlu ditentukan sebelum runtime.
Jadi meskipun ini setara:
[anObject aMethod];
[anObject performSelector:@selector(aMethod)];
Bentuk kedua memungkinkan Anda melakukan ini:
SEL aSelector = findTheAppropriateSelectorForTheCurrentSituation();
[anObject performSelector: aSelector];
sebelum Anda mengirim pesan.
performSelector:
adalah sesuatu yang mungkin hanya Anda lakukan jika Anda mengimplementasikan target-action di kelas Anda. Saudara kandung performSelectorInBackground:withObject:
dan performSelectorOnMainThread:withObject:waitUntilDone:
seringkali lebih berguna. Untuk menghasilkan thread latar belakang, dan untuk memanggil kembali hasil ke thread utama dari thread latar belakang tersebut.
performSelector
juga berguna untuk menyembunyikan peringatan kompilasi. Jika Anda mengetahui bahwa metode tersebut ada (seperti setelah menggunakan respondsToSelector
), Xcode akan berhenti mengatakan "mungkin tidak menanggapi your_selector
". Hanya saja, jangan menggunakannya alih - alih mencari tahu penyebab sebenarnya dari peringatan tersebut. ;)
Untuk contoh yang sangat mendasar dalam pertanyaan ini,
[object doSomething];
[object performSelector:@selector(doSomething)];
tidak ada perbedaan tentang apa yang akan terjadi. doSomething akan dieksekusi secara sinkron oleh objek. Hanya "doSomething" adalah metode yang sangat sederhana, yang tidak mengembalikan apa pun, dan tidak memerlukan parameter apa pun.
apakah itu sesuatu yang sedikit lebih rumit, seperti:
(void)doSomethingWithMyAge:(NSUInteger)age;
semuanya akan menjadi rumit, karena [object doSomethingWithMyAge: 42];
tidak bisa lagi dipanggil dengan varian apa pun dari "performSelector", karena semua varian dengan parameter hanya menerima parameter objek.
Pemilih di sini akan menjadi "doSomethingWithMyAge:" tetapi setiap upaya untuk melakukannya
[object performSelector:@selector(doSomethingWithMyAge:) withObject:42];
tidak bisa dikompilasi. meneruskan NSNumber: @ (42) bukannya 42, juga tidak akan membantu, karena metode ini mengharapkan tipe C dasar - bukan objek.
Selain itu, ada varian performSelector hingga 2 parameter, tidak lebih. Sedangkan metode berkali-kali memiliki lebih banyak parameter.
Saya telah menemukan bahwa meskipun varian sinkron dari performSelector:
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
selalu mengembalikan objek, saya juga dapat mengembalikan BOOL atau NSUInteger sederhana, dan berhasil.
Salah satu dari dua kegunaan utama performSelector adalah untuk membuat nama metode yang ingin Anda jalankan secara dinamis, seperti yang dijelaskan di jawaban sebelumnya. Sebagai contoh
SEL method = NSSelectorFromString([NSString stringWithFormat:@"doSomethingWithMy%@:", @"Age");
[object performSelector:method];
Kegunaan lainnya, adalah untuk mengirimkan pesan ke objek secara asinkron, yang akan dieksekusi nanti pada runloop saat ini. Untuk ini, ada beberapa varian performSelector lainnya.
- (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;
(ya saya mengumpulkannya dari beberapa kategori kelas Foundation, seperti NSThread, NSRunLoop dan NSObject)
Tiap varian memiliki perilaku khususnya, tetapi semuanya memiliki kesamaan (setidaknya saat waitUntilDone disetel ke NO). Panggilan "performSelector" akan segera kembali, dan pesan ke objek hanya akan diletakkan di runloop saat ini setelah beberapa waktu.
Karena eksekusi tertunda - tentu saja tidak ada nilai pengembalian yang tersedia dari metode pemilih, oleh karena itu nilai pengembalian - (void) di semua varian asinkron ini.
Saya harap saya menutupi ini entah bagaimana ...
@ennuikiller tepat. Pada dasarnya, penyeleksi yang dibuat secara dinamis berguna ketika Anda tidak (dan biasanya tidak mungkin) mengetahui nama metode yang akan Anda panggil saat Anda mengompilasi kode.
Satu perbedaan utama adalah bahwa -performSelector:
dan teman (termasuk varian multi-utas dan tertunda ) agak terbatas karena dirancang untuk digunakan dengan metode dengan parameter 0-2. Misalnya, memanggil -outlineView:toolTipForCell:rect:tableColumn:item:mouseLocation:
dengan 6 parameter dan mengembalikan NSString
cukup berat, dan tidak didukung oleh metode yang disediakan.
NSInvocation
objek.
performSelector:
dan teman-teman semua mengambil argumen objek, artinya Anda tidak dapat menggunakannya untuk memanggil (misalnya) setAlphaValue:
, karena argumennya adalah pelampung.
Penyeleksi agak mirip dengan pointer fungsi dalam bahasa lain. Anda menggunakannya saat tidak tahu pada waktu kompilasi metode mana yang ingin Anda panggil saat runtime. Juga, seperti pointer fungsi, mereka hanya merangkum bagian kata kerja dari pemanggilan. Jika metode tersebut memiliki parameter, Anda harus meneruskannya juga.
An NSInvocation
memiliki tujuan yang sama, kecuali bahwa ia mengikat lebih banyak informasi. Tidak hanya menyertakan bagian kata kerja, ini juga menyertakan objek target dan parameter. Ini berguna saat Anda ingin memanggil metode pada objek tertentu dengan parameter tertentu, bukan untuk saat ini tetapi di masa mendatang. Anda dapat membuat yang sesuai NSInvocation
dan memecatnya nanti.
Ada perbedaan halus lainnya di antara keduanya.
[object doSomething]; // is executed right away
[object performSelector:@selector(doSomething)]; // gets executed at the next runloop
Berikut adalah kutipan dari Dokumentasi Apple
"performSelector: withObject: afterDelay: Menjalankan selektor yang ditentukan pada thread saat ini selama siklus run loop berikutnya dan setelah periode penundaan opsional. Karena metode ini menunggu hingga siklus run loop berikutnya untuk menjalankan pemilih, metode ini menyediakan penundaan mini otomatis dari kode yang saat ini sedang dijalankan. Beberapa antrian pemilih dilakukan satu demi satu dalam urutan antrian mereka. "
performSelector:withObject:afterDelay:
, tetapi pertanyaan dan cuplikan Anda gunakan performSelector:
, yang merupakan metode yang sama sekali berbeda. Dari dokumen untuk itu: <quote> performSelector:
Metodenya sama dengan mengirim aSelector
pesan langsung ke penerima. </quote>
performSelector/performSelector:withObject/performSelector:withObject:afterDelay
semua berperilaku sama yang merupakan kesalahan.