web-dev-qa-db-de.com

Aufrufen der Protokoll-Standardimplementierung aus der regulären Methode

Ich frage mich, ob es möglich ist, so etwas zu erreichen.
Ich habe einen Spielplatz wie folgt:

protocol Foo {
    func testPrint()
}

extension Foo {
    func testPrint() {
        print("Protocol extension call")
    }
}

struct Bar: Foo {
    func testPrint() {
        // Calling self or super go call default implementation
        self.testPrint()
        print("Call from struct")
    }
}


let sth = Bar()
sth.testPrint()

Ich kann eine Standardimplementierung in extension bereitstellen, aber was ist, wenn Bar alles benötigt, was in der Standardimplementierung enthalten ist, und zusätzliche Dinge?
Es ähnelt dem Aufruf von super.-Methoden in classes, um die Anforderung der Implementierung jeder Eigenschaft usw. zu erfüllen. Ich sehe jedoch keine Möglichkeit, dies mit structs zu erreichen.

64
cojoj

Ich weiß nicht, ob Sie immer noch nach einer Antwort suchen, aber Sie können die Funktion aus der Protokolldefinition entfernen, Ihr Objekt in Foo umwandeln und dann die Methode darauf aufrufen:

protocol Foo { 
    // func testPrint() <- comment this out or remove it
}

extension Foo {
    func testPrint() {
        print("Protocol extension call")
    }
}

struct Bar: Foo {
    func testPrint() {
        print("Call from struct")
        (self as Foo).testPrint() // <- cast to Foo and you'll get the  default
                                  //    function defined in the extension
    }
}

Bar().testPrint()

// Output:    "Call from struct"
//            "Protocol extension call"

Aus irgendeinem Grund funktioniert es nur, wenn die Funktion nicht als Teil des Protokolls deklariert ist, sondern in einer Erweiterung des Protokolls definiert ist. Stelle dir das vor. Aber es geht doch.

73
Aaron Rasmussen

Nun, Sie könnten einen geschachtelten Typ erstellen, der dem Protokoll entspricht, ihn instanziieren und die Methode für diesen Typ aufrufen (es spielt keine Rolle, dass Sie nicht auf die Daten Ihres Typs zugreifen können, da die Implementierung in der Protokollerweiterung ohnehin nicht darauf verweisen kann). Aber es ist keine Lösung, die ich als elegant bezeichnen würde.

struct Bar: Foo {
    func testPrint() {
        // Calling default implementation
        struct Dummy : Foo {}
        let dummy = Dummy()
        dummy.testPrint()
        print("Call from struct")
    }
}
7
Thorsten Karrer

Falls Ihr Protokoll associatedType- oder Self-Anforderungen hat, funktioniert die Besetzung nicht. Erstellen Sie eine "Schatten" -Standardimplementierung, die sowohl die reguläre Standardimplementierung als auch der konforme Typ aufrufen können.

protocol Foo { 
    associatedType Bar
}

extension Foo {
    func testPrint() {
        defaultTestPrint()
    }
}

fileprivate extension Foo { // keep this as private as possible
    func defaultTestPrint() {
        // default implementation
    }
}

struct Bar: Foo {
    func testPrint() {
        // specialized implementation
        defaultTestPrint()
    }
}
2
David James

Danke für den Beitrag! Wenn Sie die Funktionsdefinition in das Protokoll aufnehmen, wird beim Umwandeln des Objekts als Protokoll nur die Version der Funktion des Objekts angezeigt. Da Sie es in sich selbst aufrufen, erhalten Sie die neue Adresse von Apple ...

Ich habe eine Version wie diese ausprobiert:

import UIKit
protocol MyProc
{
}

protocol MyFuncProc
{
    func myFunc()
}

extension MyProc
{
    func myFunc()
    {
        print("Extension Version")
    }
}

struct MyStruct: MyProc, MyFuncProc
{
    func myFunc()
    {
        print("Structure Version")
        (self as MyProc).myFunc()
    }
}

(MyStruct() as MyFuncProc).myFunc()

Dies ergibt eine Ausgabe von:

Structure Version
Extension Version
2
Jim Malak

was denkst du über eine solche Lösung?

protocol Foo {
    func testPrint()
}

extension Foo {
    func testPrint() {
        defaultTestPrint()
    }

    func defaultTestPrint() {
        print("Protocol extension call")
    }
}

struct Bar: Foo {
    func testPrint() {
        // Calling self or super go call default implementation
        defaultTestPrint()
        print("Call from struct")
    }
}


let sth = Bar()
sth.testPrint()
0
Amin Madani