Swift'te mümkün mü? Değilse, bunu yapmak için bir geçici çözüm var mı?
Swift'te mümkün mü? Değilse, bunu yapmak için bir geçici çözüm var mı?
Yanıtlar:
protocol MyProtocol {
func doSomething()
}
extension MyProtocol {
func doSomething() {
/* return a default value or just leave empty */
}
}
struct MyStruct: MyProtocol {
/* no compile error */
}
Avantajları
Hiçbir Objective-C çalışma zamanı söz konusu değildir (en azından açıkça değil). Bu, yapıları, sıralamaları ve NSObject
sınıf dışı yapılara uyum sağlayabileceğiniz anlamına gelir . Ayrıca, bu güçlü jenerik sistemden yararlanabileceğiniz anlamına gelir.
Böyle bir protokole uyan türlerle karşılaştığınızda her zaman tüm gereksinimlerin karşılandığından emin olabilirsiniz . Her zaman ya somut uygulama ya da varsayılan uygulama. "Arayüzler" veya "sözleşmeler" diğer dillerde böyle davranır.
Dezavantajları
Olmayan için Void
gereksinimleri, makul bir varsayılan değeri olması gerekir her zaman mümkün değildir. Ancak, bu sorunla karşılaştığınızda, bu tür bir gereksinimin gerçekten varsayılan bir uygulaması olmaması veya API tasarımı sırasında bir hata yaptığınız anlamına gelir.
En azından özel dönüş değerleriyle ilgili sorunu ele almadan, varsayılan bir uygulama ile hiçbir uygulama arasında ayrım yapamazsınız . Aşağıdaki örneği düşünün:
protocol SomeParserDelegate {
func validate(value: Any) -> Bool
}
Yalnızca dönen varsayılan bir uygulama sağlarsanız true
- ilk bakışta iyi olur. Şimdi, aşağıdaki sahte kodu düşünün:
final class SomeParser {
func parse(data: Data) -> [Any] {
if /* delegate.validate(value:) is not implemented */ {
/* parse very fast without validating */
} else {
/* parse and validate every value */
}
}
}
Böyle bir optimizasyon yapmanın bir yolu yoktur - temsilcinizin bir yöntem uygulayıp uygulamadığını bilemezsiniz.
Bu sorunun üstesinden gelmek için birkaç farklı yol olmasına rağmen (isteğe bağlı kapanışları kullanarak, farklı işlemler için birkaç isim vermek için farklı temsilci nesneleri), bu örnek sorunu açıkça ortaya koymaktadır.
@objc optional
.@objc protocol MyProtocol {
@objc optional func doSomething()
}
class MyClass: NSObject, MyProtocol {
/* no compile error */
}
Avantajları
Dezavantajları
Tüm uygun tiplerin Objective-C uyumlu olmasını gerektirerek protokolünüzün yeteneklerini ciddi şekilde sınırlar . Bu, yalnızca devralınan sınıfların bu NSObject
protokole uygun olabileceği anlamına gelir . Yapı yok, numara yok, ilişkili tür yok.
Her zaman isteğe bağlı olarak çağrılarak veya uygun türün uygulanıp uygulanmadığını denetleyerek isteğe bağlı bir yöntemin uygulanıp uygulanmadığını kontrol etmelisiniz . Bu, sık sık isteğe bağlı yöntemler arıyorsanız, çok sayıda kaynak plakası getirebilir.
respondsToSelector
?
optional func doSomething(param: Int?)
Swift 2 ve sonrasında, bir protokolün varsayılan uygulamalarını eklemek mümkündür. Bu protokollerde isteğe bağlı yöntemlerin yeni bir yolunu oluşturur.
protocol MyProtocol {
func doSomethingNonOptionalMethod()
func doSomethingOptionalMethod()
}
extension MyProtocol {
func doSomethingOptionalMethod(){
// leaving this empty
}
}
İsteğe bağlı protokol yöntemleri oluşturmak için gerçekten hoş bir yol değildir, ancak protokol geri çağrılarında yapıları kullanma olanağı sunar.
Burada küçük bir özet yazdım: https://www.avanderlee.com/swift-2-0/optional-protocol-methods/
İsteğe bağlı değiştiricinin ve @objc özelliğinin nasıl kullanılacağına ilişkin bazı yanıtlar bulunduğundan bağlı gereksinim protokolünü tanımlamak için isteğe isteğe bağlı protokol tanımlayan protokol uzantılarının nasıl kullanılacağı hakkında bir örnek vereceğim.
Aşağıdaki kod Swift 3. *.
/// Protocol has empty default implementation of the following methods making them optional to implement:
/// `cancel()`
protocol Cancelable {
/// default implementation is empty.
func cancel()
}
extension Cancelable {
func cancel() {}
}
class Plane: Cancelable {
//Since cancel() have default implementation, that is optional to class Plane
}
let plane = Plane()
plane.cancel()
// Print out *United Airlines can't cancelable*
Lütfen protokol uzantısı yöntemlerinin Objective-C kodu tarafından çağrılamadığını ve Swift ekibinin bunu düzeltmeyeceğini unutmayın. https://bugs.swift.org/browse/SR-492
Burada, protokole "@objc" olarak işaretleme ile ilgili diğer cevaplar, hızlı özel türler kullanılırken çalışmaz.
struct Info {
var height: Int
var weight: Int
}
@objc protocol Health {
func isInfoHealthy(info: Info) -> Bool
}
//Error "Method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C"
Hızlı ile iyi çalışan isteğe bağlı protokolleri bildirmek için işlevleri işlevler yerine değişkenler olarak bildirin.
protocol Health {
var isInfoHealthy: (Info) -> (Bool)? { get set }
}
Ve sonra protokolü aşağıdaki gibi uygulayın
class Human: Health {
var isInfoHealthy: (Info) -> (Bool)? = { info in
if info.weight < 200 && info.height > 72 {
return true
}
return false
}
//Or leave out the implementation and declare it as:
//var isInfoHealthy: (Info) -> (Bool)?
}
Daha sonra "?" işlevin uygulanıp uygulanmadığını kontrol etmek
func returnEntity() -> Health {
return Human()
}
var anEntity: Health = returnEntity()
var isHealthy = anEntity.isInfoHealthy(Info(height: 75, weight: 150))?
//"isHealthy" is true
İşte heyet örneği ile somut bir örnek.
Protokolünüzü kurun:
@objc protocol MyProtocol:class
{
func requiredMethod()
optional func optionalMethod()
}
class MyClass: NSObject
{
weak var delegate:MyProtocol?
func callDelegate()
{
delegate?.requiredMethod()
delegate?.optionalMethod?()
}
}
Temsilciyi bir sınıfa ayarlayın ve Protokolü uygulayın. İsteğe bağlı yöntemin uygulanması gerekmediğine bakın.
class AnotherClass: NSObject, MyProtocol
{
init()
{
super.init()
let myInstance = MyClass()
myInstance.delegate = self
}
func requiredMethod()
{
}
}
Önemli bir şey, isteğe bağlı yöntemin isteğe bağlı olması ve bir "?" arama yaparken. İkinci soru işaretinden bahsedin.
delegate?.optionalMethod?()
In Swift 3.0
@objc protocol CounterDataSource {
@objc optional func increment(forCount count: Int) -> Int
@objc optional var fixedIncrement: Int { get }
}
Zaman kazandıracak.
@objc
Tüm üyelerde neden herhangi bir kaynağa ihtiyaç var?
required
bayrak, ancak hatalarla denedim : required
sadece 'init' bildirimlerinde kullanılabilir.
optional
Her yöntemden önce anahtar kelime eklemeniz gerekir .@objc
sadece protokol olarak değil, işaretlemenizi gerektirir .
Antoine'nin cevabının mekaniğini göstermek için:
protocol SomeProtocol {
func aMethod()
}
extension SomeProtocol {
func aMethod() {
print("extensionImplementation")
}
}
class protocolImplementingObject: SomeProtocol {
}
class protocolImplementingMethodOverridingObject: SomeProtocol {
func aMethod() {
print("classImplementation")
}
}
let noOverride = protocolImplementingObject()
let override = protocolImplementingMethodOverridingObject()
noOverride.aMethod() //prints "extensionImplementation"
override.aMethod() //prints "classImplementation"
İsteğe bağlı bir protokol yöntemini nasıl uygulayabileceğinizi sormadan önce , neden bir protokol yöntemi uygulayacağınızı sormanız gerektiğini düşünüyorum .
Hızlı protokolleri klasik nesne yönelimli programlamada bir Arayüz olarak düşünürsek , isteğe bağlı yöntemler çok mantıklı değildir ve belki de daha iyi bir çözüm, varsayılan uygulamayı oluşturmak veya protokolü bir dizi protokole (belki de bazı miras ilişkileriyle) ayırmak olacaktır. (protokoller arasındaki yöntemlerin olası kombinasyonunu temsil etmek için).
Daha fazla okuma için, bu konu hakkında mükemmel bir genel bakış sunan https://useyourloaf.com/blog/swift-optional-protocol-methods/ adresine bakın .
Orijinal sorudan biraz konu dışı, ama Antoine'nin fikrini geliştiriyor ve birisine yardımcı olabileceğini düşündüm.
Ayrıca, hesaplanan özellikleri protokol uzantılarına sahip yapılar için isteğe bağlı yapabilirsiniz.
Protokolde bir özelliği isteğe bağlı yapabilirsiniz
protocol SomeProtocol {
var required: String { get }
var optional: String? { get }
}
Protokol uzantısına kukla hesaplanmış özelliği uygulayın
extension SomeProtocol {
var optional: String? { return nil }
}
Ve şimdi isteğe bağlı özellik uygulanmış veya uygulanmamış yapıları kullanabilirsiniz
struct ConformsWithoutOptional {
let required: String
}
struct ConformsWithOptional {
let required: String
let optional: String?
}
Ayrıca , blogumdaki Swift protokollerinde isteğe bağlı özelliklerin nasıl yapılacağını da yazdım , bu da Swift 2 sürümlerinde bir şeylerin değişmesi durumunda güncellenmeye devam edeceğim.
İsteğe bağlı ve gerekli temsilci yöntemleri nasıl oluşturulur.
@objc protocol InterViewDelegate:class {
@objc optional func optfunc() // This is optional
func requiredfunc()// This is required
}
İşte SADECE hızlı Sınıflar için çok basit bir örnek, yapılar veya numaralandırmalar için değil. Protokol yönteminin isteğe bağlı olduğunu, oyunda iki isteğe bağlı zincirleme seviyesine sahip olduğunu unutmayın. Ayrıca protokolü benimseyen sınıfın beyanında @objc özelliğine ihtiyaç vardır.
@objc protocol CollectionOfDataDelegate{
optional func indexDidChange(index: Int)
}
@objc class RootView: CollectionOfDataDelegate{
var data = CollectionOfData()
init(){
data.delegate = self
data.indexIsNow()
}
func indexDidChange(index: Int) {
println("The index is currently: \(index)")
}
}
class CollectionOfData{
var index : Int?
weak var delegate : CollectionOfDataDelegate?
func indexIsNow(){
index = 23
delegate?.indexDidChange?(index!)
}
}
delegate?.indexDidChange?(index!)
?
protocol CollectionOfDataDelegate{ func indexDidChange(index: Int) }
o zaman soru işareti olmadan çağırırsınız: delegate?.indexDidChange(index!)
Bir protokolde bir yöntem için isteğe bağlı bir gereksinim ayarladığınızda, buna uyan Tür bu yöntemi uygulamıyor olabilir , bu yüzden ?
uygulama kontrol etmek için kullanılır ve hiçbiri yoksa program çökmez. @Unheilig
weak var delegate : CollectionOfDataDelegate?
(zayıf referansı sağlamak?)
delegate?
Kullanımınıza ilişkin açıklamanızı cevabınıza ekleyebilir misiniz ? Bu bilgi, gelecekte başkaları için gerçekten orada olmalıdır. Bunu onaylamak istiyorum, ama bu bilgi gerçekten cevapta olmalı.
Eğer bunu hızlı bir şekilde yapmak istiyorsanız, örneğin Swift türleriyle yapı gibi bir Swift türünü döndürürseniz, en iyi yol varsayılan bir uygulama parçacığı sağlamaktır.
misal :
struct magicDatas {
var damagePoints : Int?
var manaPoints : Int?
}
protocol magicCastDelegate {
func castFire() -> magicDatas
func castIce() -> magicDatas
}
extension magicCastDelegate {
func castFire() -> magicDatas {
return magicDatas()
}
func castIce() -> magicDatas {
return magicDatas()
}
}
o zaman her fonksiyonu tanımlamaksızın protokol uygulayabilirsiniz
Hızlı protokolde isteğe bağlı yöntem oluşturmanın iki yolu vardır.
1 - İlk seçenek @objc özelliğini kullanarak protokolünüzü işaretlemektir. Bu, yalnızca sınıflar tarafından benimsenebileceği anlamına gelse de, bireysel yöntemleri şu şekilde isteğe bağlı olarak işaretlediğiniz anlamına gelir:
@objc protocol MyProtocol {
@objc optional func optionalMethod()
}
2 - Daha hızlı bir yol: Bu seçenek daha iyidir. Bunun gibi hiçbir şey yapmayan isteğe bağlı yöntemlerin varsayılan uygulamalarını yazın.
protocol MyProtocol {
func optionalMethod()
func notOptionalMethod()
}
extension MyProtocol {
func optionalMethod() {
//this is a empty implementation to allow this method to be optional
}
}
Swift, isteğe bağlı olmasını istediğimiz yöntemler için varsayılan bir uygulama sağlamamıza izin veren uzantı adı verilen bir özelliğe sahiptir.
Bir seçenek bunları isteğe bağlı işlev değişkenleri olarak saklamaktır:
struct MyAwesomeStruct {
var myWonderfulFunction : Optional<(Int) -> Int> = nil
}
let squareCalculator =
MyAwesomeStruct(myWonderfulFunction: { input in return input * input })
let thisShouldBeFour = squareCalculator.myWonderfulFunction!(2)
Protokolde işlevi tanımlayın ve bu protokol için uzantı oluşturun, ardından isteğe bağlı olarak kullanmak istediğiniz işlev için boş uygulama oluşturun.
Optional
Protocol
Hızlı bir şekilde tanımlamak için , bu protokol içindeki bildirim ve / bildirimden @objc
önce anahtar kelime kullanmalısınız . Aşağıda bir protokolün İsteğe Bağlı Özelliğinin bir örneği verilmiştir.Protocol
attribute
method
@objc protocol Protocol {
@objc optional var name:String?
}
class MyClass: Protocol {
// No error
}
@optional
Yöntemlerin veya özelliklerin önüne koyun .
@optional
doğru anahtar kelime bile değil. Bu optional
, sınıfı ve protokolü @objc
özniteliğe bildirmeniz gerekir .