我需要将一个实现带有相关类型的协议的对象传递给一个接受协议的方法。这在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中根本不可能使用这种用例?
答案 0 :(得分:0)
此动态分派和直接分派Magic对此检查swift-method-dispatch
进行了详细说明动态调度是选择一个实施的过程 在运行时调用的多态操作(方法或函数)。
在protocol extension
中实现的任何方法都是直接调度的
我会解释更多
因为ShadowA
是protocol
并具有default implementation
扩展名,所以编译器的想法是“ Any class can adopt to this protocol without implement this method because it have default implementation
”
直接发送
因此,在这一行中,编译器从item那里了解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是concreate类型,因此它调用在其内部实现的test Method。如果未实现,则会调用默认实现
let a1 = SpecificA()
print(a1.test(data: 0))