Saya mencoba untuk membuat NSTimer
di Swift
tapi aku mengalami beberapa masalah.
NSTimer(timeInterval: 1, target: self, selector: test(), userInfo: nil, repeats: true)
test()
adalah fungsi di kelas yang sama.
Saya mendapatkan kesalahan di editor:
Tidak dapat menemukan kelebihan untuk 'init' yang menerima argumen yang disediakan
Ketika saya mengubah selector: test()
ke selector: nil
yang menghilang kesalahan.
Saya sudah mencoba:
selector: test()
selector: test
selector: Selector(test())
Tetapi tidak ada yang berhasil dan saya tidak dapat menemukan solusi dalam referensi.
selector: test()
akan memanggiltest
dan meneruskannya mengembalikan nilai keselector
argumen.Jawaban:
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-alihrespondsToSelector:
, dan gunakan penutupan di mana pun Anda bisa, bukanperformSelector:
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 penggantiSEL
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.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:insertSubview(_:at:)
vsinsertSubview(_:aboveSubview:)
). Tetapi jika suatu fungsi tidak memiliki parameter, satu-satunya cara untuk mendamaikannya adalah dengan menggunakanas
gips dengan tanda tangan tipe fungsi (misalnyafoo as () -> ()
vsfoo(_:)
).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 aSelector
dari string: misalnyaSelector("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 setidaknyainternal
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 lagiKeyPath
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 denganStringLiteralConvertible
, 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
.sumber
size:andShape:
,, jika argumen pertama bernama Anda mungkin memerlukanWith
, yaituinitWithData:
untukfunc init(Data data: NSData)
Berikut adalah contoh cepat tentang cara menggunakan
Selector
kelas di Swift:Perhatikan bahwa jika metode yang diteruskan sebagai string tidak berfungsi, itu akan gagal saat runtime, tidak mengkompilasi waktu, dan merusak aplikasi Anda. Hati-hati
sumber
@selector
berguna, tetapi tidak diberlakukan secara formal seperti yang Anda pikirkan. "Selektor yang tidak dideklarasikan" hanyalah peringatan dari kompiler, karena penyeleksi baru selalu dapat diperkenalkan pada saat run time. Referensi pemilih yang dapat diverifikasi / dapat dihidupkan kembali di Swift akan menjadi permintaan fitur yang baik untuk dibuat .Juga, jika kelas (Swift) Anda tidak turun dari kelas Objective-C, maka Anda harus memiliki titik dua di akhir string nama metode target dan Anda harus menggunakan properti @objc dengan metode target Anda misalnya
jika tidak, Anda akan mendapatkan kesalahan "Pemilih Tidak Dikenal" saat runtime.
sumber
Selector
kata kunci tidak wajib. Jadi dalam hal ini tanda tangan harus@objc func method(timer: NSTimer) {/*code*/}
@objc
bekerja untukku. Saya tidak perlu memasukkantimer: NSTimer
tanda tangan metode saya untuk dipanggil.Swift 2.2+ dan Swift 3 Update
Gunakan
#selector
ekspresi baru , yang menghilangkan kebutuhan untuk menggunakan string literal membuat penggunaan lebih sedikit rawan kesalahan. Sebagai referensi:menjadi
Lihat juga: Proposal Evolusi Swift
Catatan (Swift 4.0):
Jika menggunakan
#selector
Anda harus menandai fungsi sebagai@objc
Contoh:
@objc func something(_ sender: UIButton)
sumber
Cepat 4.0
Anda membuat Selector seperti di bawah ini.
1. tambahkan acara ke tombol seperti:
dan fungsinya akan seperti di bawah ini:
sumber
@objc
sebelumnyafunc
yang diperlukan dalam Swift 4.Untuk pembaca masa depan, saya menemukan bahwa saya mengalami masalah dan mendapatkan
unrecognised selector sent to instance
kesalahan yang disebabkan oleh menandai targetfunc
sebagai pribadi.The
func
HARUS dapat dilihat secara publik untuk dipanggil oleh objek dengan referensi ke pemilih.sumber
objc
sebelum deklarasi. Mis:@objc private func foo() { ...
maka Anda dapat menggunakan"foo"
selektor sebanyak yang Anda sukainternal
, dengan demikian tidak menentukan pengubah akses apa pun. Saya sering menggunakan pola ini://MARK: - Selector Methods\n extension MyController {\n func buttonPressed(_ button: UIButton) {
Kalau-kalau ada orang lain yang memiliki masalah yang sama dengan NSTimer di mana tidak ada jawaban lain yang memperbaiki masalah ini, sangat penting untuk menyebutkan bahwa, jika Anda menggunakan kelas yang tidak mewarisi dari NSObject baik secara langsung atau jauh di dalam hierarki ( mis. file swift yang dibuat secara manual), tidak ada jawaban lain yang akan berfungsi walaupun ditentukan sebagai berikut:
Tanpa mengubah apa pun selain membuat kelas mewarisi dari NSObject saya berhenti mendapatkan kesalahan "Selektor tidak dikenal" dan membuat logika saya berfungsi seperti yang diharapkan.
sumber
Jika Anda ingin melewatkan parameter ke fungsi dari NSTimer maka berikut ini solusinya:
Sertakan titik dua dalam teks pemilih (tester :), dan parameter Anda masuk ke userInfo.
Fungsi Anda harus menggunakan NSTimer sebagai parameter. Kemudian cukup ekstrak userInfo untuk mendapatkan parameter yang lulus.
sumber
scheduledTimerWith...
secara otomatis menambahkannya ke runloop saat ini - jadi tidak ada perilaku aneh di sini sama sekali;)Selektor adalah representasi internal dari nama metode di Objective-C. Dalam Objective-C "@selector (methodName)" akan mengubah metode kode sumber menjadi tipe data SEL. Karena Anda tidak dapat menggunakan sintaks pemilih di Swift (rickster ada di sana), Anda harus secara manual menentukan nama metode sebagai objek String secara langsung, atau dengan meneruskan objek String ke tipe Selector. Berikut ini sebuah contoh:
atau
sumber
Swift 4.1
Dengan sampel gerakan tap
Lihat dokumen Apple untuk detail lebih lanjut tentang: Ekspresi Selektor
sumber
sumber
// Segarkan Metode Kontrol
sumber
Sejak Swift 3.0 diterbitkan, bahkan sedikit lebih halus untuk menyatakan targetAction yang sesuai
sumber
Ketika menggunakan
performSelector()
/addtarget()/NStimer.scheduledTimerWithInterval()
metode metode Anda (cocok dengan pemilih) harus ditandai sebagaiUntuk Swift 2.2, Anda perlu menulis '#selector ()' alih-alih nama string dan selector sehingga kemungkinan kesalahan ejaan dan kerusakan karena itu tidak akan ada lagi. Di bawah ini adalah contohnya
sumber
Anda membuat Selector seperti di bawah ini.
1.
2.
Perhatikan bahwa sintaks @selector hilang dan diganti dengan String sederhana yang menamai metode yang akan dipanggil. Ada satu area di mana kita semua bisa menyetujui verbositas menghalangi. Tentu saja, jika kita menyatakan bahwa ada metode target yang disebut flatButtonPressed: lebih baik kita menulis satu:
atur timer:
Agar lengkap, inilah flatButtonPressed
sumber
Saya menemukan banyak jawaban ini sangat membantu tetapi tidak jelas bagaimana melakukan ini dengan sesuatu yang bukan tombol. Saya menambahkan pengenal isyarat ke dalam UILabel dengan cepat dan berjuang sehingga inilah yang saya temukan bekerja untuk saya setelah membaca semuanya di atas:
Di mana "Pemilih" dinyatakan sebagai:
Perhatikan bahwa ini bersifat publik dan saya tidak menggunakan sintaks Selector () tetapi dimungkinkan untuk melakukan ini juga.
sumber
Menggunakan #selector akan memeriksa kode Anda pada waktu kompilasi untuk memastikan metode yang ingin Anda panggil benar-benar ada. Bahkan lebih baik, jika metode ini tidak ada, Anda akan mendapatkan kesalahan kompilasi: Xcode akan menolak untuk membangun aplikasi Anda, sehingga membuang sumber bug lain yang mungkin ada.
sumber
Mungkin berguna untuk mencatat di mana Anda mengatur kontrol yang memicu tindakan penting.
Misalnya, saya telah menemukan bahwa ketika mengatur UIBarButtonItem, saya harus membuat tombol di dalam viewDidLoad atau saya akan mendapatkan pengecualian pemilih yang tidak dikenal.
sumber
Ubah sebagai penamaan string sederhana dalam metode yang memanggil sintaks pemilih
Setelah itu, ketik tes func ().
sumber
selector
adalah kata dariObjective-C
dunia dan Anda dapat menggunakannya dariSwift
memiliki kemungkinan untuk meneleponObjective-C
dariSwift
itu memungkinkan Anda untuk mengeksekusi beberapa kode saat runtimeSebelum
Swift 2.2
sintaksnya adalah:Karena nama fungsi dilewatkan
Selector
sebagai parameter String ("foo"), tidak mungkin untuk memeriksa nama dalam waktu kompilasi . Akibatnya, Anda bisa mendapatkan kesalahan runtime:Setelah
Swift 2.2+
sintaksnya adalah:Pelengkapan otomatis Xcode membantu Anda memanggil metode yang tepat
sumber
Untuk Swift 3
// Kode sampel untuk membuat timer
sumber
Pemilih dalam Swift 4:
sumber
Untuk cepat 3
Deklarasi fungsi di kelas yang sama:
sumber
self
pemilih. Ini seharusnya cukup:let timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(test), userInfo: nil, repeats: true)