Bagaimana cara membuat pemilih secara dinamis saat runtime dengan Objective-C?


93

Saya tahu cara membuat SELwaktu kompilasi menggunakan @selector(MyMethodName:)tetapi yang ingin saya lakukan adalah membuat selektor secara dinamis dari file NSString. Apakah ini mungkin?

Apa yang saya bisa lakukan:

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

Yang ingin saya lakukan: (pseudo code, ini jelas tidak berfungsi)

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

Saya telah mencari dokumen Apple API, tetapi belum menemukan cara yang tidak bergantung pada @selector(myTarget:)sintaks waktu kompilasi .

Jawaban:


180

Saya bukan programmer Objective-C, hanya simpatisan, tapi mungkin NSSelectorFromString adalah yang Anda butuhkan. Disebutkan secara eksplisit dalam Referensi Runtime yang dapat Anda gunakan untuk mengonversi string menjadi selektor.


5
Saya perlu memoles Google-fu saya. itulah yang saya (atau tidak mungkin) cari.
— craigb

Yah, saya masih memiliki tautan yang beterbangan di bookmark saya sejak saya membaca dokumen Objective-C 2.0 beberapa hari yang lalu.
— Torsten Marek

40

Menurut dokumentasi XCode, psuedocode Anda pada dasarnya sudah benar.

Paling efisien untuk menetapkan nilai ke variabel SEL pada waktu kompilasi dengan direktif @selector (). Namun, dalam beberapa kasus, program mungkin perlu mengubah string karakter menjadi pemilih saat runtime. Ini dapat dilakukan dengan fungsi NSSelectorFromString:

setWidthHeight = NSSelectorFromString(aBuffer);

Edit: Nyebelin, terlalu lambat. : P


2
NSStringFromSelector(@"doWork")mengubahnya dengan cara lain (hanya fyi)
— bendytree

8
Saya pikir maksud Anda, NSStringFromSelector (@selector (doWork))
— jpswain

Dan apa yang seharusnya dilakukan oleh selektor itu? Bukankah kita harus menentukan blok atau sesuatu?
— pengguna4951

12

Saya harus mengatakan bahwa ini sedikit lebih rumit daripada yang mungkin disarankan oleh jawaban responden sebelumnya ... jika Anda memang benar-benar ingin membuat pemilih ... bukan hanya "panggil satu" yang "Anda miliki" .. .

Anda perlu membuat penunjuk fungsi yang akan dipanggil oleh metode "baru" Anda .. jadi untuk metode seperti [self theMethod:(id)methodArg];, Anda akan menulis ...

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

lalu Anda perlu membuat IMP blok secara dinamis, kali ini, meneruskan, "self", the SEL, dan argumen apa pun ...

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

dan menambahkannya ke kelas Anda, bersama dengan tanda tangan metode yang akurat untuk seluruh pengisap (dalam kasus ini "v@:@" , void return, pemanggil objek, argumen objek)

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

Anda dapat melihat beberapa contoh bagus dari jenis runtime shenanigans ini , di salah satu repo saya, di sini.


5

Saya tahu ini telah dijawab sejak lama, tetapi saya tetap ingin berbagi. Ini bisa dilakukan dengan menggunakan sel_registerNamejuga.

Kode contoh dalam pertanyaan dapat ditulis ulang seperti ini:

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

2
Sebenarnya, yang NSSelectorFromStringdisebutkan oleh @ torsten-marek menggunakan di sel_registerNamebawah tenda. appledev : "NSSelectorFromString meneruskan representasi karakter berenkode UTF-8 dari aSelectorName ke sel_registerName dan mengembalikan nilai yang dikembalikan oleh fungsi itu"
— PLG
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.