Saya mencoba mengubah kode sumber proyek saya dari Swift 3 ke Swift 4. Satu peringatan yang diberikan Xcode kepada saya adalah tentang penyeleksi saya.
Misalnya, saya menambahkan target ke tombol menggunakan pemilih biasa seperti ini:
button.addTarget(self, action: #selector(self.myAction), for: .touchUpInside)
Ini peringatan yang ditunjukkannya:
Argumen '#selector' merujuk ke metode instance 'myAction ()' di 'ViewController' yang bergantung pada inferensi atribut '@objc' yang tidak digunakan lagi dalam Swift 4
Tambahkan '@objc' untuk mengekspos metode instance ini ke Objective-C
Sekarang, menekan Fix
pada pesan kesalahan melakukan ini untuk fungsi saya:
// before
func myAction() { /* ... */ }
// after
@objc func myAction() { /* ... */ }
Saya tidak benar-benar ingin mengubah nama semua fungsi saya untuk memasukkan @objc
tanda dan saya berasumsi itu tidak perlu.
Bagaimana cara menulis ulang pemilih untuk mengatasi penghinaan?
Pertanyaan terkait:
@objc
yang sekarang diperlukan dalam rangka untuk mengekspos mereka untuk obj-C, dan karena itu digunakan dengan pemilih.@objc
? Itu agak menjengkelkan, tapi saya biasanya membuat fungsi-fungsi ini pribadi, mengharuskan saya untuk menandainya sebagai@objc
anyways.@objcMembers
untuk mengekspos semua anggota yang kompatibel dengan Obj-C ke Obj-C, tetapi saya tidak akan menyarankan itu kecuali Anda benar-benar membutuhkan seluruh kelas Anda untuk diekspos.Jawaban:
Perbaiki-itu benar - tidak ada tentang pemilih yang dapat Anda ubah untuk membuat metode yang merujuk ke terkena Objective-C.
Seluruh alasan untuk peringatan ini sejak awal adalah hasil dari SE-0160 . Sebelum Swift 4,
internal
atau lebih tinggi anggota yang kompatibel dengan Objective-C dariNSObject
kelas inherit disimpulkan@objc
dan karenanya terkena Objective-C, oleh karena itu memungkinkan mereka untuk dipanggil menggunakan penyeleksi (karena runtime Obj-C diperlukan untuk mencari metode ini implementasi untuk pemilih tertentu).Namun dalam Swift 4, ini tidak lagi terjadi. Hanya deklarasi yang sangat spesifik sekarang disimpulkan menjadi
@objc
, misalnya, menimpa@objc
metode, implementasi@objc
persyaratan protokol dan deklarasi dengan atribut yang menyiratkan@objc
, seperti@IBOutlet
.Motivasi di balik ini, sebagaimana dirinci dalam proposal terkait di atas , adalah pertama-tama untuk mencegah kelebihan metode dalam
NSObject
mewarisi kelas yang saling bertabrakan karena memiliki penyeleksi yang identik. Kedua, ini membantu mengurangi ukuran biner dengan tidak harus menghasilkan thunks untuk anggota yang tidak perlu terkena Obj-C, dan ketiga meningkatkan kecepatan penghubung dinamis.Jika Anda ingin mengekspos anggota ke Obj-C, Anda harus menandainya sebagai
@objc
, misalnya:(migrator harus melakukan ini secara otomatis untuk Anda dengan penyeleksi ketika menjalankan dengan opsi "meminimalkan inferensi" yang dipilih)
Untuk memaparkan sekelompok anggota ke Obj-C, Anda dapat menggunakan
@objc extension
:Ini akan mengekspos semua anggota yang didefinisikan di dalamnya untuk Obj-C, dan memberikan kesalahan pada setiap anggota yang tidak dapat terkena Obj-C (kecuali secara eksplisit ditandai sebagai
@nonobjc
).Jika Anda memiliki kelas di mana Anda membutuhkan semua anggota yang kompatibel dengan Obj-C untuk terkena Obj-C, Anda dapat menandai kelas sebagai
@objcMembers
:Sekarang, semua anggota yang dapat disimpulkan
@objc
akan menjadi. Namun, saya tidak akan menyarankan melakukan ini kecuali Anda benar - benar perlu semua anggota terkena Obj-C, mengingat kelemahan yang disebutkan di atas memiliki anggota yang tidak perlu terpapar.sumber
@IBAction
juga secara otomatis@objc
? itu tidak terjadi sampai sekarang tetapi itu akan logis. EDIT: nvm, proposal dengan jelas menyatakan bahwa@IBAction
cukup untuk suatu metode@objc
.Sebagai Dokumentasi Resmi Apple . Anda perlu menggunakan @objc untuk memanggil Metode Pemilihan Anda.
sumber
Pada, saya pikir Swift 4.2, yang perlu Anda lakukan hanyalah menetapkan @IBAction ke metode Anda dan Anda dapat menghindari anotasi @objc konyol ini
`` `
sumber
Seperti yang telah disebutkan dalam jawaban lain, tidak ada cara untuk menghindari
@objc
anotasi bagi pemilih.Tetapi peringatan yang disebutkan dalam OP dapat dibungkam dengan mengambil langkah-langkah berikut:
Off
di bawah ini adalah tangkapan layar yang menggambarkan langkah-langkah yang disebutkan di atas:
Semoga ini membantu
sumber
Jika Anda memerlukan anggota c yang obyektif di pengontrol tampilan Anda, tambahkan saja @objcMembers di bagian atas pengontrol tampilan. Dan Anda dapat menghindari ini dengan menambahkan IBAction dalam kode Anda.
Pastikan untuk menghubungkan outlet ini di storyboard.
sumber