Gambaran:
- Saya memiliki protokol P1 yang menyediakan implementasi default dari salah satu fungsi opsional Objective-C.
- Ketika saya menyediakan implementasi default dari fungsi opsional, ada peringatan
Peringatan Penyusun:
Non-'@objc' method 'presentationController(_:viewControllerForAdaptivePresentationStyle:)' does not satisfy optional requirement of '@objc' protocol 'UIAdaptivePresentationControllerDelegate'
Versi: kapan:
- Cepat: 3
- Xcode: 8 (rilis publik)
Upaya yang dilakukan:
- Mencoba menambahkan
@objc
tetapi tidak membantu
Pertanyaan:
- Bagaimana cara mengatasi ini?
- Apakah ada solusi?
Kode:
@objc protocol P1 : UIAdaptivePresentationControllerDelegate {
}
extension P1 where Self : UIViewController {
func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
return UIViewController()
}
}
class A : UIViewController, P1 {
}
swift
swift3
swift-protocols
pengguna1046037
sumber
sumber
@objc
Jawaban:
Meskipun saya pikir saya bisa menjawab pertanyaan Anda, itu bukan jawaban yang Anda sukai.
TL; DR:
@objc
fungsi saat ini mungkin tidak ada dalam ekstensi protokol. Anda dapat membuat kelas dasar sebagai gantinya, meskipun itu bukan solusi yang ideal.Ekstensi Protokol dan Objective-C
Pertama, pertanyaan / jawaban ini ( Can Swift Method Defined on Extensions on Protocols Accessed in Objective-c ) tampaknya menyarankan bahwa karena cara ekstensi protokol dikirim di bawah tenda, metode yang dideklarasikan dalam ekstensi protokol tidak terlihat oleh
objc_msgSend()
fungsi tersebut, dan oleh karena itu tidak terlihat oleh kode Objective-C. Karena metode yang Anda coba tentukan dalam ekstensi Anda harus terlihat oleh Objective-C (sehingga AndaUIKit
dapat menggunakannya), ia berteriak pada Anda untuk tidak menyertakannya@objc
, tetapi begitu Anda memasukkannya, ia akan berteriak kepada Anda karena@objc
tidak diizinkan di ekstensi protokol. Ini mungkin karena ekstensi protokol saat ini tidak dapat dilihat oleh Objective-C.Kita juga dapat melihat bahwa pesan kesalahan setelah kita menambahkan
@objc
status "@objc hanya dapat digunakan dengan anggota kelas, protokol @objc, dan ekstensi konkret kelas." Ini bukan kelas; ekstensi ke protokol @objc tidak sama dengan definisi protokol itu sendiri (yaitu dalam persyaratan), dan kata "konkret" akan menyarankan bahwa ekstensi protokol tidak dihitung sebagai ekstensi kelas yang konkret.Solusi
Sayangnya, ini cukup banyak mencegah Anda dari menggunakan ekstensi protokol ketika implementasi default harus terlihat oleh kerangka kerja Objective-C. Pada awalnya, saya pikir mungkin
@objc
tidak diizinkan dalam ekstensi protokol Anda karena Swift Compiler tidak dapat menjamin bahwa tipe yang sesuai akan menjadi kelas (meskipun Anda telah menentukannya secara khususUIViewController
). Jadi saya memasangclass
persyaratanP1
. Ini tidak berhasil.Mungkin satu-satunya solusi adalah dengan hanya menggunakan kelas dasar daripada protokol di sini, tetapi ini jelas tidak sepenuhnya ideal karena kelas mungkin hanya memiliki satu kelas dasar tetapi sesuai dengan beberapa protokol.
Jika Anda memilih untuk mengikuti rute ini, harap pertimbangkan pertanyaan ini ( Metode Protokol Opsional ObjC Swift 3 Tidak Disebut dalam Subkelas ) ke dalam akun. Tampaknya masalah lain saat ini di Swift 3 adalah bahwa subclass tidak secara otomatis mewarisi implementasi persyaratan protokol opsional dari superclass mereka. Jawaban atas pertanyaan tersebut menggunakan adaptasi khusus
@objc
untuk menyiasatinya.Melaporkan Masalah
Saya pikir ini sudah dibahas di antara mereka yang mengerjakan proyek sumber terbuka Swift, tetapi Anda dapat yakin mereka mengetahuinya dengan menggunakan Reporter Bug Apple , yang kemungkinan pada akhirnya akan menuju ke Tim Inti Swift, atau reporter bug Swift . Namun, salah satu dari ini mungkin menganggap bug Anda terlalu luas atau sudah diketahui. Tim Swift juga dapat menganggap apa yang Anda cari sebagai fitur bahasa baru, dalam hal ini Anda harus memeriksa milis terlebih dahulu .
Memperbarui
Pada Desember 2016, masalah ini dilaporkan ke komunitas Swift. Masalah tersebut masih ditandai sebagai terbuka dengan prioritas menengah, tetapi komentar berikut telah ditambahkan:
Karena protokol Anda berada dalam modul yang sama dengan ekstensi Anda, bagaimanapun, Anda mungkin dapat melakukan ini di versi Swift yang akan datang.
Perbarui 2
Pada bulan Februari 2017, masalah ini secara resmi ditutup sebagai "Won't Do" oleh salah satu anggota Swift Core Team dengan pesan berikut:
Memperluas
NSObject
atau bahkanUIViewController
tidak akan mencapai apa yang Anda inginkan, tetapi sayangnya tampaknya tidak akan menjadi mungkin.Di masa depan (yang sangat) panjang, kami mungkin dapat menghilangkan ketergantungan pada
@objc
metode sepenuhnya, tetapi waktu itu kemungkinan besar tidak akan datang dalam waktu dekat karena kerangka kerja Cocoa saat ini tidak ditulis di Swift (dan tidak bisa sampai memiliki ABI yang stabil) .Perbarui 3
Mulai Musim Gugur 2019, ini menjadi lebih sedikit masalah karena semakin banyak kerangka kerja Apple yang ditulis di Swift. Misalnya, jika Anda menggunakan
SwiftUI
alih-alihUIKit
, Anda menghindari masalah sepenuhnya karena@objc
tidak akan pernah diperlukan saat merujuk ke suatuSwiftUI
metode.Kerangka kerja Apple yang ditulis di Swift meliputi:
Orang akan berharap pola ini berlanjut seiring waktu karena Swift secara resmi ABI dan modul stabil pada Swift 5.0 dan 5.1, masing-masing.
sumber
Swift 4
tidak ada alternatif lain seperti sekarang.Saya baru saja mengalami ini setelah mengaktifkan 'stabilitas modul' (mengaktifkan 'Membangun perpustakaan untuk distribusi') dalam kerangka kerja yang cepat yang saya gunakan.
Apa yang saya miliki adalah sesuatu seperti ini:
Fungsi dalam ekstensi mengalami kesalahan berikut:
Metode instance '@objc' dalam ekstensi subclass 'LessAwesomeClass' memerlukan iOS 13.0.0
Metode non - '@ objc' 'niceDelegateFunc' tidak memenuhi persyaratan protokol '@objc' 'GreatDelegate'
Memindahkan fungsi ke dalam kelas daripada di ekstensi menyelesaikan masalah.
sumber
Berikut solusi lain. Saya mengalami masalah ini juga, dan belum bisa beralih dari UIKit ke SwiftUI. Memindahkan implementasi default ke kelas dasar umum juga bukan pilihan bagi saya. Implementasi default saya cukup ekstensif jadi saya benar-benar tidak ingin semua kode itu diduplikasi. Solusi yang akhirnya saya gunakan adalah menggunakan fungsi pembungkus dalam protokol, dan kemudian cukup memanggil fungsi tersebut dari setiap kelas. Tidak cantik, tetapi mungkin lebih baik daripada alternatifnya, tergantung situasinya. Kode Anda akan terlihat seperti ini:
sumber