Sorunuza cevap verebileceğimi düşünsem de hoşunuza gidecek bir cevap değil.
TL; DR: @objc
işlevler şu anda protokol uzantılarında olmayabilir. Bunun yerine bir temel sınıf oluşturabilirsiniz, ancak bu ideal bir çözüm değildir.
Protokol Uzantıları ve Amaç-C
İlk olarak, bu soru / cevap ( Hedef-c'de Erişilen Protokollerde Eklentilerde Tanımlanan Can Swift Yöntemi ), protokol uzantılarının başlık altında gönderilme şekli nedeniyle, protokol uzantılarında bildirilen yöntemlerin objc_msgSend()
işlev tarafından görülemediğini ve bu nedenle Objective-C kodu tarafından görülmez. Uzantınızda tanımlamaya çalıştığınız yöntemin Objective-C tarafından görülebilmesi gerektiğinden (bu yüzden UIKit
onu kullanabilirsiniz), dahil etmediğiniz için size bağırır @objc
, ancak bir kez dahil ettiğinizde size bağırır çünkü @objc
içeri girmesine izin verilmez. protokol uzantıları. Bunun nedeni muhtemelen protokol uzantılarının şu anda Objective-C tarafından görülememesidir.
Ayrıca, @objc
"@objc yalnızca sınıfların üyeleri, @objc protokolleri ve sınıfların somut uzantıları ile kullanılabilir" durumlarını eklediğimizde hata mesajını görebiliriz . Bu bir sınıf değil; @objc protokolüne bir uzantı, protokol tanımının kendisinde (yani gereksinimlerde) olmakla aynı değildir ve "somut" kelimesi, bir protokol uzantısının somut bir sınıf uzantısı olarak sayılmadığını gösterir.
Geçici çözüm
Ne yazık ki, bu, varsayılan uygulamaların Objective-C çerçevelerine görünür olması gerektiğinde protokol uzantılarını kullanmanızı neredeyse tamamen engeller. İlk başta, @objc
Swift Derleyici uygun türlerin sınıflar olacağını garanti edemeyeceği için protokol uzantınızda izin verilmediğini düşündüm (özellikle belirtmiş olsanız bile UIViewController
). Bu yüzden bir class
şart koydum P1
. Bu işe yaramadı.
Belki de tek geçici çözüm, burada bir protokol yerine basit bir sınıf kullanmaktır, ancak bu kesinlikle ideal değildir çünkü bir sınıf yalnızca tek bir temel sınıfa sahip olabilir ancak birden çok protokole uyabilir.
Bu rotaya gitmeyi seçerseniz, lütfen bu soruyu ( Swift 3 ObjC İsteğe Bağlı Protokol Yöntemi Alt Sınıfta Çağrılmadı ) dikkate alın. Görünüşe göre Swift 3'teki diğer bir güncel sorun, alt sınıfların üst sınıflarının isteğe bağlı protokol gereksinimi uygulamalarını otomatik olarak devralmamasıdır. Bu soruların cevabı, @objc
etrafından dolaşmak için özel bir uyarlama kullanır .
Sorunun Bildirilmesi
Bunun Swift açık kaynak projelerinde çalışanlar arasında zaten tartışıldığını düşünüyorum, ancak sonunda Swift Core Ekibine gidecek olan Apple'ın Bug Reporter'ını veya Swift'in hata muhabirini kullanarak onların farkında olduklarından emin olabilirsiniz . Ancak bunlardan herhangi biri, hatanızı çok geniş veya zaten biliniyor bulabilir. Swift ekibi, aradığınızı yeni bir dil özelliği olarak da düşünebilir, bu durumda önce posta listelerine göz atmalısınız .
Güncelleme
Aralık 2016'da, bu sorun Swift topluluğuna bildirildi . Sorun, orta öncelikli olarak hala açık olarak işaretlendi, ancak aşağıdaki yorum eklendi:
Bu amaçlanmıştır. Uzatma protokole uygunluktan sonra eklenebildiğinden, her evlat edene yöntemin uygulamasını eklemenin bir yolu yoktur. Sanırım uzantı protokol ile aynı modülde ise buna izin verebiliriz.
Protokolünüz uzantınız ile aynı modülde olduğu için, bunu Swift'in gelecekteki bir sürümünde yapabilirsiniz.
Güncelleme 2
Şubat 2017'de bu sayı , Swift Core Ekibi üyelerinden biri tarafından aşağıdaki mesajla "Yapmayacak" olarak resmen kapatıldı :
Bu bilinçlidir: protokol uzantıları, Objective-C çalışma zamanının sınırlamaları nedeniyle @objc giriş noktalarını tanıtamaz. NSObject'e @objc giriş noktaları eklemek istiyorsanız, NSObject'i genişletin.
Genişletmek, NSObject
hatta UIViewController
tam olarak istediğinizi başaramayacak ama maalesef mümkün olacak gibi görünmüyor.
(Çok) uzun vadeli bir gelecekte, @objc
yöntemlere olan bağımlılığı tamamen ortadan kaldırabiliriz , ancak Cocoa çerçeveleri şu anda Swift ile yazılmadığından (ve kararlı bir ABI'ye sahip olana kadar olamaz) bu zaman muhtemelen yakın zamanda gelmeyecektir. .
Güncelleme 3
Sonbahar 2019'dan itibaren bu daha az sorun olmaya başladı çünkü Swift'de gittikçe daha fazla Apple çerçevesi yazılıyor. Örneğin, SwiftUI
yerine kullanırsanız UIKit
, problemden tamamen kaçarsınız çünkü @objc
bir SwiftUI
yönteme atıfta bulunurken asla gerekli olmayacaktır .
Swift ile yazılan Apple çerçeveleri şunları içerir:
- SwiftUI
- RealityKit
- Birleştirmek
- CryptoKit
Bu modelin zamanla devam etmesi beklenebilir, çünkü Swift resmi olarak ABI ve sırasıyla Swift 5.0 ve 5.1'den itibaren modül kararlı.
@objc