Swift sendiri tidak menggunakan penyeleksi - beberapa pola desain yang di Objective-C memanfaatkan penyeleksi bekerja berbeda di Swift. (Misalnya, gunakan rantai tambahan pada jenis protokol atau is
/ as
pengujian alih-alih respondsToSelector:
, dan gunakan penutupan di mana pun Anda bisa, bukan performSelector:
untuk keamanan jenis / memori yang lebih baik.)
Tetapi masih ada sejumlah API berbasis ObjC penting yang menggunakan penyeleksi, termasuk penghitung waktu dan pola sasaran / tindakan. Swift menyediakan Selector
tipe untuk bekerja dengannya. (Swift secara otomatis menggunakan ini sebagai pengganti SEL
tipe ObjC .)
Di Swift 2.2 (Xcode 7.3) dan yang lebih baru (termasuk Swift 3 / Xcode 8 dan Swift 4 / Xcode 9):
Anda bisa membuat Selector
dari tipe fungsi Swift menggunakan #selector
ekspresi.
let timer = Timer(timeInterval: 1, target: object,
selector: #selector(MyClass.test),
userInfo: nil, repeats: false)
button.addTarget(object, action: #selector(MyClass.buttonTapped),
for: .touchUpInside)
view.perform(#selector(UIView.insertSubview(_:aboveSubview:)),
with: button, with: otherButton)
Hal hebat tentang pendekatan ini? Referensi fungsi diperiksa oleh kompiler Swift, sehingga Anda dapat menggunakan #selector
ekspresi hanya dengan pasangan kelas / metode yang benar-benar ada dan memenuhi syarat untuk digunakan sebagai penyeleksi (lihat "Ketersediaan pemilih" di bawah). Anda juga bebas membuat referensi fungsi Anda hanya sespesifik yang Anda butuhkan, sesuai aturan Swift 2.2+ untuk penamaan tipe fungsi .
(Ini sebenarnya merupakan perbaikan dari @selector()
arahan ObjC , karena pemeriksaan kompiler -Wundeclared-selector
hanya memverifikasi bahwa ada pemilih bernama. Referensi fungsi Swift yang Anda berikan untuk #selector
memeriksa keberadaan, keanggotaan dalam kelas, dan ketik tanda tangan.)
Ada beberapa peringatan tambahan untuk referensi fungsi yang Anda sampaikan ke #selector
ekspresi:
- Beberapa fungsi dengan nama dasar yang sama dapat dibedakan dengan label parameternya menggunakan sintaksis yang disebutkan di atas untuk referensi fungsi (misalnya
insertSubview(_:at:)
vs insertSubview(_:aboveSubview:)
). Tetapi jika suatu fungsi tidak memiliki parameter, satu-satunya cara untuk mendamaikannya adalah dengan menggunakan as
gips dengan tanda tangan tipe fungsi (misalnya foo as () -> ()
vs foo(_:)
).
- Ada sintaks khusus untuk pasangan pengambil / penyetel properti di Swift 3.0+. Misalnya, diberi
var foo: Int
, Anda dapat menggunakan #selector(getter: MyClass.foo)
atau #selector(setter: MyClass.foo)
.
Catatan umum:
Kasus di mana #selector
tidak berfungsi, dan penamaan: Terkadang Anda tidak memiliki referensi fungsi untuk membuat pemilih dengan (misalnya, dengan metode yang terdaftar secara dinamis di runtime ObjC). Dalam kasus itu, Anda bisa membuat a Selector
dari string: misalnya Selector("dynamicMethod:")
- meskipun Anda kehilangan pemeriksaan validitas kompilator. Ketika Anda melakukannya, Anda harus mengikuti aturan penamaan ObjC, termasuk titik dua ( :
) untuk setiap parameter.
Ketersediaan pemilih : Metode yang dirujuk oleh pemilih harus diekspos ke runtime ObjC. Dalam Swift 4, setiap metode yang diekspos ke ObjC harus memiliki deklarasi diawali dengan @objc
atribut. (Dalam versi sebelumnya Anda mendapatkan atribut itu secara gratis dalam beberapa kasus, tetapi sekarang Anda harus mendeklarasikannya secara eksplisit.)
Ingatlah bahwa private
simbol tidak terkena runtime juga - metode Anda harus memiliki setidaknya internal
visibilitas.
Jalur utama: Ini terkait tetapi tidak persis sama dengan penyeleksi. Ada sintaks khusus untuk ini di Swift 3, juga: misalnya chris.valueForKeyPath(#keyPath(Person.friends.firstName))
. Lihat SE-0062 untuk detailnya. Dan lebih banyak lagi KeyPath
hal-hal di Swift 4 , jadi pastikan Anda menggunakan API berbasis KeyPath yang tepat dan bukan penyeleksi jika perlu.
Anda dapat membaca lebih lanjut tentang penyeleksi di bawah Berinteraksi dengan Objective-C APIs dalam Menggunakan Swift dengan Cocoa dan Objective-C .
Catatan: Sebelum Swift 2.2, Selector
sesuaikan dengan StringLiteralConvertible
, jadi Anda mungkin menemukan kode lama tempat string kosong diteruskan ke API yang mengambil pemilih. Anda akan ingin menjalankan "Konversi ke Sintaks Swift Saat Ini" di Xcode untuk mendapatkannya #selector
.
selector: test()
akan memanggiltest
dan meneruskannya mengembalikan nilai keselector
argumen.