2

同じ関数名を持つ複数のプロトコルがあります。一部のプロトコルには型が関連付けられており、非ジェネリック プロトコルの場合のように関数を呼び出す方法がわかりません。エラーが発生します: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)
   }
}

汎用プロトコル拡張から関数を具体的に呼び出すにはどうすればよいですか?

4

1 に答える 1

3

プロトコルをジェネリックに変えるか (以下を参照)、これらのプロトコルの型消しゴムを作成することで簡単に達成できますが、これは設計上の問題があり、クラスや拡張機能を再設計する必要があることを強く示唆しています。このような衝突は、とMyStructによって複数の方向に引っ張られているため、それ自体があまりにも多くのことを行っていることを強く示唆しています。代わりに、ここに 2 つのオブジェクトがあるはずです。(継承ではなく合成。)MyProtocol1MyProtocol2

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の講演に興味があるかもしれません。これと同様の問題についてです。

于 2016-04-25T13:06:43.817 に答える