多个协议扩展中的功能不明确?

Ambiguous functions in multiple protocol extensions?

我有多个具有相同函数名称的协议。某些协议具有关联类型,我无法像在非通用协议中那样弄清楚如何调用这些函数。我收到错误: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)
   }
}

如何从通用协议扩展中专门调用该函数?

通过将协议变成通用协议(见下文)或为这些协议创建一个 type eraser 很容易实现,但这非常强烈地表明你有设计问题,你应该重新设计你的类 and/or 个扩展名。像这样的碰撞强烈表明 MyStruct 本身做了太多事情,因为它被 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 演讲感兴趣。这是关于这个和类似的问题。