The NSObject
Metode performSelector:withObject:afterDelay:
memungkinkan saya untuk memanggil metode pada objek dengan argumen objek setelah waktu tertentu. Ini tidak dapat digunakan untuk metode dengan argumen non-objek (misalnya ints, floats, struct, non-object pointers, dll.).
Apa cara paling sederhana untuk mencapai hal yang sama dengan metode dengan argumen non-objek? Saya tahu bahwa untuk reguler performSelector:withObject:
, solusinya adalah dengan menggunakan NSInvocation
(yang sebenarnya sangat rumit). Tapi saya tidak tahu bagaimana menangani bagian "penundaan".
Terima kasih,
objective-c
cocoa
pengguna102008
sumber
sumber
Jawaban:
Inilah yang biasa saya sebut sesuatu yang tidak dapat saya ubah menggunakan NSInvocation:
sumber
[theMovie setOrientation: UIInterfaceOrientationPortrait animated:NO]
? Atau maksud Andainvoke
pesan tersebut ada dalam metode yang Anda lakukan setelah penundaan?Cukup bungkus float, boolean, int atau yang serupa di NSNumber.
Untuk struct, saya tidak tahu solusi yang berguna, tetapi Anda dapat membuat kelas ObjC terpisah yang memiliki struct tersebut.
sumber
nil
untukBOOL
parameter untuk menerimaNO
(FALSE
)JANGAN GUNAKAN JAWABAN INI. SAYA HANYA MENINGGALKANNYA UNTUK KEPERLUAN SEJARAH. LIHAT KOMENTAR DI BAWAH.
Ada trik sederhana jika itu adalah parameter BOOL.
Berikan nol untuk TIDAK dan diri sendiri untuk YA. nil dilemparkan ke nilai BOOL dari NO. self dilemparkan ke nilai BOOL dari YES.
Pendekatan ini rusak jika itu adalah selain parameter BOOL.
Mengasumsikan diri adalah seorang UIView.
sumber
if ()
tes padanya, tetapi dapat dibayangkan bahwa beberapa kode akan bergantung padanya menjadi 0 atau 1, dan dengan demikian menang perlakukan beberapa nilai alamat yang besar sama dengan 1 (YA).self
dengan alamat seperti0x0123400
. Dengan pendekatan ini, Anda TIDAK akan mendapatkan insting YA dalam 0,4% kasus. Lebih buruk lagi, dengan probabilitas ini, solusi ini dapat lulus semua tes dan muncul nanti.Mungkin NSValue , cukup pastikan pointer Anda masih valid setelah penundaan (mis. Tidak ada objek yang dialokasikan di stack).
sumber
NSValue
(jika mungkin) seperti yang diharapkantype
?Saya tahu ini adalah pertanyaan lama tetapi jika Anda membuat iOS SDK 4+, Anda dapat menggunakan blok untuk melakukan ini dengan sedikit usaha dan membuatnya lebih mudah dibaca:
sumber
PerformSelector: WithObject selalu mengambil objek, jadi untuk meneruskan argumen seperti int / double / float dll ..... Anda dapat menggunakan sesuatu seperti ini.
Dengan cara yang sama Anda dapat menggunakan [NSNumber numberWithInt:] dll .... dan dalam metode penerimaan Anda dapat mengonversi nomor ke dalam format Anda sebagai [number int] atau [number double].
sumber
Blok adalah jalan yang harus ditempuh. Anda dapat memiliki parameter kompleks, jenis keamanan, dan itu jauh lebih sederhana dan lebih aman daripada kebanyakan jawaban lama di sini. Misalnya, Anda bisa menulis:
Pemblokiran memungkinkan Anda untuk menangkap daftar parameter arbitrer, objek referensi, dan variabel.
Implementasi Backing (dasar):
Contoh:
Lihat juga jawaban Michael (+1) untuk contoh lainnya.
sumber
Saya akan selalu merekomendasikan agar Anda menggunakan NSMutableArray sebagai objek untuk diteruskan. Ini karena Anda kemudian dapat melewatkan beberapa objek, seperti tombol yang ditekan dan nilai lainnya. NSNumber, NSInteger dan NSString hanyalah wadah dari beberapa nilai. Pastikan bahwa ketika Anda mendapatkan objek dari larik yang Anda rujuk ke tipe penampung yang benar. Anda harus meneruskan kontainer NS. Di sana Anda dapat menguji nilainya. Ingat bahwa kontainer menggunakan isEqual saat nilainya dibandingkan.
sumber
Saya juga ingin melakukan ini, tetapi dengan metode yang menerima parameter BOOL. Membungkus nilai bool dengan NSNumber, GAGAL MELULAI NILAI. Saya tidak tahu kenapa.
Jadi saya akhirnya melakukan peretasan sederhana. Saya meletakkan parameter yang diperlukan dalam fungsi dummy lain dan memanggil fungsi itu menggunakan performSelector, di mana withObject = nil;
sumber
-performSelector[...]
metode mengharapkan objek (bukan tipe data primitif), dan tidak tahu bahwa selektor yang dipanggil menerima boolean, mungkin alamat (nilai penunjuk) dariNSNumber
instance secara membabi buta 'dilemparkan' keBOOL
(= bukan nol, yaituTRUE
). Mungkin runtime bisa lebih pintar dari ini dan mengenali nol boolean yang dibungkus denganNSNumber
!Saya menemukan bahwa cara tercepat (tapi agak kotor) untuk melakukan ini adalah dengan memanggil objc_msgSend secara langsung. Namun, berbahaya untuk memanggilnya secara langsung karena Anda perlu membaca dokumentasinya dan memastikan bahwa Anda menggunakan varian yang benar untuk tipe nilai yang dikembalikan dan karena objc_msgSend didefinisikan sebagai vararg untuk kenyamanan kompilator tetapi sebenarnya diimplementasikan sebagai perekat perakitan cepat . Berikut beberapa kode yang digunakan untuk memanggil metode delegasi - [delegate integerDidChange:] yang menggunakan argumen integer tunggal.
Ini pertama kali menyimpan selektor karena kita akan merujuknya beberapa kali dan akan mudah membuat kesalahan ketik. Kemudian memverifikasi bahwa delegasi benar-benar menanggapi pemilih - ini mungkin protokol opsional. Ini kemudian membuat jenis penunjuk fungsi yang menentukan tanda tangan sebenarnya dari pemilih. Perlu diingat bahwa semua pesan Objective-C memiliki dua argumen pertama yang tersembunyi, objek yang sedang dikirimi pesan dan selektor yang sedang dikirim. Kemudian kita membuat penunjuk fungsi dari tipe yang sesuai dan mengaturnya untuk menunjuk ke fungsi objc_msgSend yang mendasarinya. Perlu diingat bahwa jika nilai yang dikembalikan adalah float atau struct, Anda perlu menggunakan varian objc_msgSend yang berbeda. Terakhir, kirim pesan menggunakan mesin yang sama dengan yang digunakan Objective-C di bawah lembaran.
sumber
Anda bisa menggunakan NSTimer untuk memanggil pemilih:
sumber
yourMethod:
dalam contoh Anda adalah pengatur waktu itu sendiri, dan Anda belum mengirimkan apa punuserInfo
. Bahkan jika kamu benar-benar menggunakanuserInfo
, kamu masih harus mengemas nilainya, seperti yang disarankan oleh bahaya dan Remus Rusanu.Memanggil performSelector dengan NSNumber atau NSValue lain tidak akan berfungsi. Alih-alih menggunakan nilai NSValue / NSNumber, ini akan secara efektif mentransmisikan pointer ke int, float, atau apa pun dan menggunakannya.
Tetapi solusinya sederhana dan jelas. Buat NSInvocation dan panggil
[invocation performSelector:@selector(invoke) withObject:nil afterDelay:delay]
sumber
Mungkin ... ok, sangat mungkin, saya melewatkan sesuatu, tetapi mengapa tidak membuat tipe objek saja, katakanlah NSNumber, sebagai wadah untuk variabel tipe non-objek Anda, seperti CGFloat?
sumber