2016-01-18 13 views
7

ho trovato un comportamento interessante che sembra come un insetto ...Swift protocollo di estensione metodo di spedizione con superclasse e sottoclasse

Sulla base del comportamento descritto i seguenti articoli:

https://medium.com/ios-os-x-development/swift-protocol-extension-method-dispatch-6a6bf270ba94

http://nomothetis.svbtle.com/the-ghost-of-swift-bugs-future

L'output non è quello che mi aspetto, quando aggiungo SomeSuperclass anziché adottare direttamente il protocollo.

protocol TheProtocol { 
    func method1() 
} 

extension TheProtocol { 
    func method1() { 
     print("Called method1 from protocol extension") 
    } 
    func method2NotInProtocol() { 
     print("Called method2NotInProtocol from protocol extension") 
    } 
} 

// This is the difference - adding a superclass 
class SomeSuperclass: TheProtocol { 
} 

// It works as expected when it simply adopts TheProtocol, but not when it inherits from a class that adopts the protocol 
class MyClass: SomeSuperclass { 
    func method1() { 
     print("Called method1 from MyClass implementation") 
    } 
    func method2NotInProtocol() { 
     print("Called method2NotInProtocol from MyClass implementation") 
    } 
} 

let foo: TheProtocol = MyClass() 
foo.method1() // expect "Called method1 from MyClass implementation", got "Called method1 from protocol extension" 
foo.method2NotInProtocol() // Called method2NotInProtocol from protocol extension 

Sai se questo è un bug o di progettazione? Un collega ha suggerito che forse l'estensione dell'ereditarietà e delle estensioni del protocollo potrebbe non funzionare come previsto. Intendevo utilizzare l'estensione del protocollo per fornire un'implementazione predefinita ... se non riesco a farlo, allora dovrò purtroppo contrassegnarlo come @objc e tornare a un protocollo opzionale.

+1

Possibile duplicato di [Invio metodo di estensione protocollo in Swift 2.0] (http://stackoverflow.com/questions/32734403/protocol-extension-method-dispatch-in-swift-2-0) – mbelsky

risposta

1

Dal post The Ghost of Swift Bugs Future, ecco le regole per la spedizione delle estensioni del protocollo che sono menzionate alla fine del post.

  1. IF del tipo derivato di una variabile è il protocollo:
  2. E il metodo è definito nel protocollo originale THEN attuazione del tipo runtime è chiamato, indipendentemente dal fatto esiste un'implementazione predefinita nell'estensione .
  3. E il metodo non è definito nel protocollo originale, ALLORA viene chiamata l'implementazione predefinita .
  4. ELSE SE il tipo inferito della variabile è il tipo THEN viene richiamata l'implementazione del tipo.

Quindi, nelle tue condizioni, stai dicendo che method1() è definito nel protocollo ed è stato implementato nella sottoclasse. Ma la tua superclasse sta adottando il protocollo ma non sta implementando il metodo 1() e la sottoclasse eredita solo dalla Superclasse e non adotta direttamente i protocolli. Ecco perché credo che è la ragione quando si chiama foo.method1(), che non invoca l'attuazione della sottoclasse come affermato dal punto 1 & 2.

Ma quando lo fai,

class SomeSuperclass: TheProtocol { 
func method1(){ 
print("super class implementation of method1()")} 
} 

class MyClass : SomeSuperclass { 

override func method1() { 
    print("Called method1 from MyClass implementation") 
} 

override func method2NotInProtocol() { 
    print("Called method2NotInProtocol from MyClass implementation") 
} 
} 

e poi quando si chiama,

let foo: TheProtocol = MyClass() 
foo.method1() // Called method1 from MyClass implementation 
foo.method2NotInProtocol() 

Così che cosa potrebbe essere la soluzione per questo bug (che sembra essere un bug) è che, è necessario implementare il metodo di protocollo nella superclasse e quindi è necessario eseguire l'override del metodo di protocollo nella sottoclasse. HTH

0

Si prega di verificare il codice qui sotto:

import UIKit 

protocol TheProtocol { 
    func method1() 
    func method2NotInProtocol() 
} 

extension NSObject { 

    func method1() { 
     print("Called method1 from protocol extension") 
    } 
    func method2NotInProtocol() { 
     print("Called method2NotInProtocol from protocol extension") 
    } 
} 

// This is the difference - adding a superclass 
class SomeSuperclass :NSObject, TheProtocol { 

    override func method1() { 
     print("Called method1 from SomeSuperclass implementation") 
    } 

} 

// It works as expected when it simply adopts TheProtocol, but not when it inherits from a class that adopts the protocol 
class MyClass : SomeSuperclass { 

    override func method1() { 
     print("Called method1 from MyClass implementation") 
    } 

    override func method2NotInProtocol() { 
     print("Called method2NotInProtocol from MyClass implementation") 
    } 
} 

    let foo: TheProtocol = MyClass() 
    foo.method1() // expect "Called method1 from MyClass implementation", got "Called method1 from protocol extension" 
    foo.method2NotInProtocol() // Called method2NotInProtocol from protocol extension 

Invece di scrivere estensione a TheProtocol, scrivere l'estensione a una classe astratta (NSObject nel codice qui sopra). Funziona come previsto.