2016-04-25 12 views
1

Ich habe mehrere Protokolle, die den gleichen Funktionsnamen haben. Einige Protokolle haben zugeordnete Typen, bei denen ich nicht herausfinden kann, wie man die Funktionen aufruft, wie ich es bei nicht-generischen Protokollen mache. Ich erhalte den Fehler: Protocol 'MyProtocol1' can only be used as a generic contraint because it has Self or associated type requirementsMehrdeutige Funktionen in mehreren Protokollerweiterungen?

Hier ist, was ich versuche zu tun:

protocol Serviceable { 
    associatedtype DataType 
    func get(handler: ([DataType] -> Void)?) 
} 

struct PostService: Serviceable { 
    func get(handler: ([String] -> Void)? = nil) { 
     print("Do something...") 
    } 
} 

protocol MyProtocol1: class { 
    associatedtype ServiceType: Serviceable 
    var service: ServiceType { get } 
} 

extension MyProtocol1 { 
    func didLoad(delegate: Self) { 
     print("MyProtocol1.didLoad()") 
    } 
} 

protocol MyProtocol2: class { 

} 

extension MyProtocol2 { 
    func didLoad(delegate: MyProtocol2) { 
     print("MyProtocol2.didLoad()") 
    } 
} 

class MyViewController: UIViewController, MyProtocol1, MyProtocol2 { 
    let service = PostService() 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     didLoad(self as MyProtocol1) // Error here: Protocol 'MyProtocol1' can only be used as a generic contraint because it has Self or associated type requirements 
     didLoad(self as MyProtocol2) 
    } 
} 

Wie kann ich die Funktion von einer generischen Protokollerweiterung speziell nennen?

Antwort

2

Es ist einfach zu erreichen, indem Sie das Protokoll in ein generisches (siehe unten) oder durch die Erstellung eines type eraser für diese Protokolle, aber dies deutet sehr stark darauf hin, dass Sie ein Designproblem haben und Ihre Klassen und/oder Erweiterungen neu gestalten sollten . Eine Kollision wie diese deutet stark darauf hin, dass MyStruct zu viele Dinge selbst macht, weil sie von MyProtocol1 und MyProtocol2 in mehrere Richtungen gezogen wird. Hier sollten wahrscheinlich zwei Objekte vorhanden sein. (Zusammensetzung statt Vererbung.)

class MyStruct: MyProtocol1, MyProtocol2 { 
    let service = PostService() 

    func prot1Load<T: MyProtocol1>(t: T) { 
     t.didLoad() 
    } 

    func prot2Load<T: MyProtocol2>(t: T) { 
     t.didLoad() 
    } 
    init() { 
     prot1Load(self) 
     prot2Load(self) 
    } 
} 

Um Ihre speziellen Beispiel in den Kommentaren, würde ich Zusammensetzung verwenden, anstatt Vererbung. Sie behandeln Protokolle wie Mehrfachvererbung, die fast nie richtig ist. Erstelle stattdessen Dinge, die einem Protokoll entsprechen.

protocol LoadProviding { 
    func load() 
} 

struct MyLoader1: LoadProviding { 
    func load() { 
     print("MyLoader1.didLoad()") 
    } 
} 

struct MyLoader2: LoadProviding { 
    func load() { 
     print("MyLoader2.didLoad()") 
    } 
} 

protocol Loader { 
    var loaders: [LoadProviding] { get } 
} 

extension Loader { 
    func loadAll() { 
     for loader in loaders { 
      loader.load() 
     } 
    } 
} 

class MyStruct: Loader { 
    let service = PostService() 
    let loaders: [LoadProviding] = [MyLoader1(), MyLoader2()] 

    init() { 
     loadAll() 
    } 
} 

Natürlich müssen Sie nicht wirklich haben LoadProviding eine vollständige Struktur sein. Es könnte nur eine Funktion sein, wenn es das ist alles, was Sie brauchen:

typealias LoadProviding =() -> Void 

func myLoader1() { 
    print("MyLoader1.didLoad()") 
} 

func myLoader2() { 
    print("MyLoader2.didLoad()") 
} 

protocol Loader { 
    var loaders: [LoadProviding] { get } 
} 

extension Loader { 
    func loadAll() { 
     for loader in loaders { 
      loader() 
     } 
    } 
} 

class MyStruct: Loader { 
    let service = PostService() 
    let loaders: [LoadProviding] = [myLoader1, myLoader2] 

    init() { 
     loadAll() 
    } 
} 

Wenn Sie Zeit haben, um durch ein Video zu diesem Thema waten, können Sie im Beyond Crusty: Real World Protocols Vortrag von dotSwift interessiert sein könnten. Es geht um diese und ähnliche Probleme.

+0

Tatsächlich riecht es. Ich versuche, Mehrfachvererbung unter Verwendung der Protokollerweiterungen zu erreichen. Zum Beispiel würde ich in der 'viewDidLoad' meines' UIViewController' jede 'didLoad' Funktion jedes meiner Protokolle ausführen wollen. – TruMan1

+0

Dann sollten Sie eine Eigenschaft wie 'loader: [Loader]' haben, die die verschiedenen Initialisierungen enthält, die Sie benötigen. –

+0

Ich würde wahrscheinlich tiefer über die Namen hier nachdenken, damit sie den aktuellen Swift Style Richtlinien entsprechen, aber das obige ist immer noch so, wie ich es sicherlich angreifen würde. –

Verwandte Themen