多协议扩展中的模糊功能?

时间:2016-04-25 13:02:01

标签: swift generics swift2 protocols protocol-extension

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

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

1 个答案:

答案 0 :(得分:2)

通过将协议转换为通用协议(见下文)或通过为这些协议创建type eraser来实现它很简单,但这非常强烈地表明您遇到了设计问题而且您应该重新设计您的课程和/或扩展。像这样的碰撞强烈表明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讲话感兴趣。关于这个和类似的问题。