我需要将一个实现具有相关类型的协议的对象传递给一个接受协议的方法。这在Swift中是不可能的(直到最新的Swift 5)所以我使用类型擦除和基于this blog的影子协议。
protocol ShadowA {
func test(data: Any) -> String
}
extension ShadowA {
func test(data: Any) -> String {
return "shadow"
}
}
protocol A: ShadowA {
associatedtype AT
func test(data: AT) -> String
}
class SpecificA: A {
typealias AT = Int
func test(data: Int) -> String {
return "specific"
}
}
问题是,当我将对象传递给方法时,则调用“影子的默认实现”而不是“通用”实现。你可以检查playground看看发生了什么。
有什么问题或者这个用例在Swift中是不可能的吗?
这个动态的Dispatch和直接派遣魔术更多解释一下检查这个swift-method-dispatch
动态分派是选择在运行时调用多态操作(方法或函数)的实现的过程。
在protocol extension
中实现的任何方法都是Direct dispatched
我会解释更多
因为ShadowA
是protocol
并且扩展了default implementation
所以编译器头脑有这个暗示“Any class can adopt to this protocol without implement this method because it have default implementation
”
直接派遣
所以在这一行什么编译器从项目知道test(data:Any)
和因为item是具有默认实现的协议,所以它指示它调用直接默认实现
return "in method: \(item.test(data: 0))"
func passedIntoMethod(item: ShadowA) -> String {
return "in method: \(item.test(data: 0))"
}
也在这一行
let a2: ShadowA = SpecificA() // becuse compiler know only about a2 at this line that it is Protocol so it direct dispatch it
print(a2.test(data: 0))
动态调度
这里编译器知道a1是具体类型所以它调用在其中实现的test方法。如果没有实现,那么它将调用默认实现
let a1 = SpecificA()
print(a1.test(data: 0))