2016-04-25 13 views
1

私は同じ機能名を持つ複数のプロトコルを持っています。いくつかのプロトコルには関連するタイプがあります。非汎用プロトコルのように関数を呼び出す方法がわかりません。私はエラーを取得する:Protocol 'MyProtocol1' can only be used as a generic contraint because it has Self or associated type requirements複数のプロトコル拡張であいまいな機能がありますか?

は、ここで私がやろうとしているものです:

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

は、どのように私は、特に、一般的なプロトコル拡張から関数を呼び出すことができますか?

答えて

2

プロトコルを汎用(下記参照)にするか、これらのプロトコルにtype eraserを作成することで簡単に達成できますが、これは設計上の問題があることを強く示唆しており、クラスや拡張機能を再設計する必要があります。このような衝突は、MyProtocol1MyProtocol2で複数の方向に引かれているので、MyStructは多すぎることを強く示唆しています。ここに2つのオブジェクトがあるはずです。 (継承ではなく合成)

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

具体的な例では、継承ではなくコンポジションを使用します。あなたは多重継承のようなプロトコルを扱っていますが、これはほとんど妥当ではありません。代わりに、プロトコルに準拠したものから構成する。

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

もちろん、LoadProvidingを完全構造体にする必要はありません。それはあなたが必要とするすべてだ場合、それはただの関数のようになります。

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

あなたは、件名にビデオを通じて苦労する時間を持っている場合は、あなたがdotSwiftからBeyond Crusty: Real World Protocols話に興味があるかもしれません。それはこれと同様の問題です。

+0

確かににおいがします。私はプロトコル拡張を使用して複数の継承を達成しようとしています。例えば、私の 'UIViewController'の' viewDidLoad'では、私の各プロトコルのすべての 'didLoad'関数を実行したいと思います。 – TruMan1

+0

それから、 'let loader:[Loader]'のような、あなたが必要とする様々な初期化を含むプロパティを持つべきです。 –

+0

私はおそらく、現在のスウィフトスタイルのガイドラインと一致させるために、ここの名前についてもっと深く考えると思いますが、それでも私は確かにそれをどのように攻撃するのでしょうか。 –

関連する問題