'#selector' mengacu pada metode yang tidak diekspos ke Objective-C


105

Xcode 7.3 baru yang meneruskan parameter melalui addTarget biasanya berfungsi untuk saya, tetapi dalam hal ini memberikan kesalahan pada judul. Ada ide? Itu melempar yang lain ketika saya mencoba mengubahnya menjadi @objc

Terima kasih!

cell.commentButton.addTarget(self, action: #selector(FeedViewController.didTapCommentButton(_:)), forControlEvents: UIControlEvents.TouchUpInside)

Selektor itu menelepon

func didTapCommentButton(post: Post) {
}

3
Seperti apa tampilan baris deklarasi kelas FeedViewController? Bagaimana didTapCommentButton dideklarasikan? Kesalahan apa yang Anda dapatkan saat menambahkan @objc?
vacawama

1
Perbarui, saya mengedit posting saya. Saya jauh dari komputer yang sedang menyala sekarang jadi saya lupa pesan kesalahan yang tepat tetapi itu adalah salah satu situasi di mana XCode memberi tahu saya untuk menambahkannya kemudian melemparkan kesalahan pada keputusannya sendiri.
Echizzle

2
Apakah kelas Anda mendeklarasikan @objc, atau itu subkelas dari NSObject?
NRitH

2
Bisakah Anda mencoba menghapus tanda kurung? Ini tidak biasa mengingat Anda tidak boleh memanggil fungsi di selektor.
DanielEdrisian

Ini memecahkan masalah saya dalam
sekejap

Jawaban:


173

Dalam kasus saya, fungsi selektor adalah private. Setelah saya menghapus privatekesalahan itu hilang. Hal yang sama berlaku untuk fileprivate.

Di Swift 4
Anda perlu menambahkan @objcdeklarasi fungsi. Sampai swift 4 ini secara implisit disimpulkan.


2
Selain itu fileprivate.
hstdt

tangkapan besar @shaked
jbouaziz

@hstdt, jadi jika Anda menyetel, fileprivateapakah akan terselesaikan?
Hemang

2
@Hemang, tidak, @hstdt berarti bahwa keduanya privatetidak fileprivateakan berhasil
Gobe

Membuat func dengan dinamis lebih tepat daripada menghapus private / fileprivate.
Boon

57

Anda perlu menggunakan @objcatribut on didTapCommentButton(_:)untuk menggunakannya dengan #selector.

Anda mengatakan Anda melakukan itu tetapi Anda mendapat kesalahan lain. Dugaan saya adalah bahwa kesalahan baru itu Postbukan tipe yang kompatibel dengan Objective-C. Anda hanya dapat mengekspos metode ke Objective-C jika semua tipe argumennya, dan tipe kembaliannya, kompatibel dengan Objective-C.

Anda dapat memperbaikinya dengan membuat Postsubkelas dari NSObject, tetapi itu tidak akan menjadi masalah, karena argumen ke didTapCommentButton(_:)tidak akan menjadi a Post. Argumen ke fungsi tindakan adalah pengirim tindakan, dan pengirim itu akan commentButton, yang mungkin a UIButton. Anda harus menyatakan didTapCommentButtonseperti ini:

@objc func didTapCommentButton(sender: UIButton) {
    // ...
}

Anda kemudian akan menghadapi masalah mendapatkan yang Postsesuai dengan tombol yang disadap. Ada banyak cara untuk mendapatkannya. Ini dia.

Saya mengumpulkan (karena kode Anda mengatakan cell.commentButton) bahwa Anda sedang menyiapkan tampilan tabel (atau tampilan koleksi). Dan karena sel Anda memiliki properti non-standar bernama commentButton, saya berasumsi bahwa itu adalah UITableViewCellsubkelas khusus . Jadi anggaplah sel Anda PostCelldinyatakan seperti ini:

class PostCell: UITableViewCell {
    @IBOutlet var commentButton: UIButton?
    var post: Post?

    // other stuff...
}

Kemudian Anda dapat menjalankan hierarki tampilan dari tombol untuk menemukan PostCell, dan mendapatkan postingan darinya:

@objc func didTapCommentButton(sender: UIButton) {
    var ancestor = sender.superview
    while ancestor != nil && !(ancestor! is PostCell) {
        ancestor = view.superview
    }
    guard let cell = ancestor as? PostCell,
        post = cell.post
        else { return }

    // Do something with post here
}

Jika saya ingin menggunakannya dengan fungsi global? @objc can only be used with members of classes, @objc protocols, and concrete extensions of classes
TomSawyer

Anda tidak dapat menggunakannya dengan fungsi global.
merampok mayoff

8

Coba buat titik pemilih menunjuk ke fungsi pembungkus, yang pada gilirannya memanggil fungsi delegasi Anda. Itu berhasil untuk saya.

cell.commentButton.addTarget(self, action: #selector(wrapperForDidTapCommentButton(_:)), forControlEvents: UIControlEvents.TouchUpInside)

-

func wrapperForDidTapCommentButton(post: Post) {
     FeedViewController.didTapCommentButton(post)
}

1
Bekerja untuk saya! masih tidak yakin mengapa ini perlu tetapi saya akan menerimanya!
Paul Lehn

0

Seperti yang Anda ketahui selector[About] mengatakan bahwa Objective-Cruntime harus digunakan. Deklarasi yang ditandai sebagai privateatau fileprivatetidak diekspos ke runtime Objective-C secara default . Itulah mengapa Anda memiliki dua varian:

  1. Tandai privateatau fileprivatedeklarasi Anda dengan @objc[About]
  2. Gunakan internal, public, openakses pengubah [Tentang]
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.