我在我的框架中设置了几个协议来处理资源。在其中一个协议中,我设置了一个扩展,为decode
函数提供默认实现。显示代码和发生的事情更简单(请参阅fatalError
的调用)。在实际实现中有更多代码,但这说明了问题:
这是“基础”协议:
public protocol Resourceful {
associatedtype AssociatedResource
typealias ResourceCompletionHandler = (AssociatedResource?, Error?) -> Void
func fetch(_ completion: @escaping ResourceCompletionHandler)
}
这是Resourceful:
的通用,具体实现 open class WebResourceApiCall<Resource>: Resourceful {
public typealias AssociatedResource = Resource
public typealias FetchedResponse = (data: Data?, urlResponse: URLResponse?)
public init() {
}
public func fetch(_ completion: @escaping ResourceCompletionHandler) {
try! decode(fetched: (data: nil, urlResponse: nil))
}
public func decode(fetched: FetchedResponse) throws -> Resource {
fatalError("It ends up here, but I don't want it to!")
}
}
extension WebResourceApiCall where Resource: Decodable {
public func decode(fetched: FetchedResponse) throws -> Resource {
fatalError("This is where I want it to go...")
}
}
这就是我试图使用它的方式:
public struct Something: Decodable { }
var apiCall = WebResourceApiCall<Something>()
apiCall.fetch { _, _ in } // Implictly calls decode... but not the decode I expected it to! See fatalError() calls...
不像我希望的那样在扩展名上调用decode
,而是始终调用没有约束的“默认”decode
方法。
为什么这不按照我期望的方式工作?
提前致谢!
答案 0 :(得分:0)
Swift是一种静态调度的语言,因此要调用的decode()
函数的地址是在编译时计算的,并且由于该调用发生在该类的基本定义内,因此编译器会选择原始实现。
现在,如果您从编译器具有足够信息来选择所需实现的地方调用该方法,那么它将起作用:
var apiCall = WebResourceApiCall<Something>()
try apiCall.decode(fetched: (nil, nil))
上面的代码将从专用扩展名中调用该方法,因为此时编译器可以更好地知道其具有更专用的实现。
如果在动态调度世界中(即在协议级别)移动decode()
方法,应该可以实现所需的行为。