2015-09-16 8 views
47

Mi chiedo se sia possibile ottenere una cosa del genere.
Ho un parco giochi come questo:Chiamare l'implementazione predefinita del protocollo dal metodo normale

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() 

posso fornire un'implementazione di default in extension ma cosa succede se Bar ha bisogno di tutto ciò che è in implementazione di default, più cose aggiuntive?
È in qualche modo simile a chiamare i metodi super. in class per soddisfare i requisiti di implementazione di ogni proprietà ecc. Ma non vedo alcuna possibilità di ottenere lo stesso con structs.

+0

vorrei usare 'Foo.testPrint (auto)()' - il problema è che non riesce a causa di una segmentazione guasto (testato su 7.0 GM e 7.1 beta) – Antonio

+0

Questo è uno strano costrutto che hai presentato – cojoj

+2

Ogni metodo di istanza è un metodo alesato statico che prende un'istanza come primo parametro – Antonio

risposta

54

Non so se siete ancora alla ricerca di una risposta a questo, ma il modo per farlo è quello di rimuovere la funzione dalla definizione di protocollo, lanciare il tuo oggetto al Foo e quindi chiamare il metodo su esso:

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" 

per qualche motivo funziona solo se la funzione non è dichiarata come parte del protocollo, ma è definito nel un'estensione del protocollo. Vai a capire. Ma funziona.

+0

Sì, ho trovato questa soluzione su qualche post del blog, il che è stato molto bello dal modo in cui ... – cojoj

+0

Oh dio! Non posso credere che ti costringano a togliere la funzionalità dal protocollo! buona risposta, grazie! –

+2

Questo mi sembra un bug, non dovrebbe essere possibile ottenere un'implementazione del metodo differente semplicemente lanciando la stessa istanza. –

5

Bene, è possibile creare un tipo annidato conforme al protocollo, istanziarlo e chiamare il metodo su quello (non importa che non sia possibile accedere ai dati del proprio tipo in quanto l'implementazione all'interno dell'estensione del protocollo non può comunque farvi riferimento). Ma non è una soluzione che definirei elegante.

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

Sembra che sia l'unica possibilità in questo momento (confermata da Apple) ... Troverò un radar di funzionalità per questo come potrebbe essere utile – cojoj

1

Grazie per il post! Se metti la definizione della funzione nel protocollo, quando l'oggetto viene castato come protocollo vede solo la versione dell'oggetto della funzione e dal momento che la stai chiamando dentro si ottiene il nuovo indirizzo di Apple ...

I ha fatto provare una versione simile a questo:

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() 

questo dà una potenza di:

Structure Version 
Extension Version