ios - tag - Wie definiert man optionale Methoden im Swift-Protokoll?




title tag länge 2018 (10)

Da es einige Antworten darüber gibt, wie man den optionalen Modifikator und das @objc-Attribut verwendet , um das optionale Anforderungsprotokoll zu definieren, werde ich ein Beispiel geben, wie man Protokollerweiterungen verwendet, um das optionale Protokoll zu definieren.

Unter dem Code ist 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*

Bitte beachten Sie, dass Protokollerweiterungsmethoden nicht mit Objective-C-Code aufgerufen werden können und dass das Swift-Team es nicht beheben kann. https://bugs.swift.org/browse/SR-492

Ist es in Swift möglich? Wenn nicht, gibt es einen Workaround dafür?


Die anderen Antworten, bei denen das Protokoll als "@objc" gekennzeichnet ist, funktionieren nicht, wenn swift-spezifische Typen verwendet werden.

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"

Um optionale Protokolle zu deklarieren, die gut mit swift funktionieren, deklarieren Sie die Funktionen als Variablen anstelle von Funktionen.

protocol Health {
    var isInfoHealthy: (Info) -> (Bool)? { get set }
}

Und dann implementieren Sie das Protokoll wie folgt

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)?
}

Sie können dann "?" um zu überprüfen, ob die Funktion implementiert wurde oder nicht

func returnEntity() -> Health {
    return Human()
}

var anEntity: Health = returnEntity()

var isHealthy = anEntity.isInfoHealthy(Info(height: 75, weight: 150))? 
//"isHealthy" is true

Etwas abseits von der ursprünglichen Frage, aber es baut Antoines Idee auf und ich dachte, es könnte jemandem helfen.

Sie können berechnete Eigenschaften auch für Strukturen mit Protokollerweiterungen optional machen.

Sie können eine Eigenschaft im Protokoll optional festlegen

protocol SomeProtocol {
    var required: String { get }
    var optional: String? { get }
}

Implementieren Sie die berechnete Dummy-Eigenschaft in der Protokollerweiterung

extension SomeProtocol {
    var optional: String? { return nil }
}

Und jetzt können Sie Strukturen verwenden, bei denen die optionale Eigenschaft implementiert ist oder nicht

struct ConformsWithoutOptional {
    let required: String
}

struct ConformsWithOptional {
    let required: String
    let optional: String?
}

Ich habe auch geschrieben, wie man optionale Eigenschaften in Swift-Protokollen auf meinem Blog macht , die ich für den Fall, dass sich die Dinge durch die Swift 2-Veröffentlichungen ändern, auf dem Laufenden halte.


Hier ist ein sehr einfaches Beispiel für schnelle Klassen NUR und nicht für Strukturen oder Aufzählungen. Beachten Sie, dass die Protokollmethode optional ist und zwei Ebenen optionaler Verkettung beim Spielen aufweist. Auch die Klasse, die das Protokoll annimmt, benötigt das @objc-Attribut in ihrer Deklaration.

@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!)
    }

 }

In Swift 3.0

@objc protocol CounterDataSource {
    @objc optional func increment(forCount count: Int) -> Int
    @objc optional var fixedIncrement: Int { get }
}

Es wird Ihre Zeit sparen.


In Swift 2.0 ist es möglich, Standardimplementierungen eines Protokolls hinzuzufügen. Dies schafft eine neue Art von optionalen Methoden in Protokollen.

protocol MyProtocol {
    func doSomethingNonOptionalMethod()
    func doSomethingOptionalMethod()
}

extension MyProtocol {
    func doSomethingOptionalMethod(){ 
        // leaving this empty 
    }
}

Es ist keine wirklich nette Art, optionale Protokoll-Methoden zu erstellen, sondern gibt Ihnen die Möglichkeit, Strukturen in Protokoll-Rückrufen zu verwenden.

Ich habe hier eine kleine Zusammenfassung geschrieben: http://www.avanderlee.com/swift-2-0/optional-protocol-methods/


Setzen Sie einfach zwei Wörter, während Sie die Funktion deklarieren

@objc optional

Um die Mechanik von Antoines Antwort zu illustrieren:

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"

Hier ist ein konkretes Beispiel mit dem Delegationsmuster.

Richten Sie Ihr Protokoll ein:

@objc protocol MyProtocol:class
{
    func requiredMethod()
    optional func optionalMethod()
}

class MyClass: NSObject
{
    weak var delegate:MyProtocol?

    func callDelegate()
    {
        delegate?.requiredMethod()
        delegate?.optionalMethod?()
    }
}

Setzen Sie den Delegaten auf eine Klasse und implementieren Sie das Protokoll. Beachten Sie, dass die optionale Methode nicht implementiert werden muss.

class AnotherClass: NSObject, MyProtocol
{
    init()
    {
        super.init()

        let myInstance = MyClass()
        myInstance.delegate = self
    }

    func requiredMethod()
    {
    }
}

Eine wichtige Sache ist, dass die optionale Methode optional ist und ein "?" beim Anrufen. Erwähnen Sie das zweite Fragezeichen.

delegate?.optionalMethod?()

Wenn Sie optionale Methoden verwenden möchten, müssen Sie Ihr Protokoll mit dem @objc Attribut @objc :

@objc protocol MyProtocol {

    @objc optional func doSomething()

}

class MyClass : MyProtocol {

    // no error

}

Ansonsten verhalten sich Swift-Protokolle wie Schnittstellen zu anderen OO-Sprachen, in denen alle in Schnittstellen definierten Methoden implementiert sein müssen.





swift-extensions