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它本身做了太多事情,因为它被MyProtocol1和拉向多个方向MyProtocol2。相反,这里应该有两个对象。(组合而不是继承。)

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 回答