Swift中的Override协议扩展默认实现
您可能需要阅读https://team.goodeggs.com/overriding-swift-protocol-extension-default-implementations-d005a4428bda
这是我在Medium写作中缺席了很长时间(可能是四个月)之后的下一个故事,所以请耐心等待您。
我读过人们在使自己的Swift代码更紧凑并遵循面向协议的编程方面遇到问题。 两者都可以实现,但也有一些局限性。
让我告诉你我的情况。
在上面的代码中,我有一个协议X
,我想让UIView实现它。 然后,要实现X
, UIView
必须提供方法x()
,我们知道。
但是,假设我们要override
UIStackView
的x()
实现,它是UIView
子类。 问题来了。 扩展不能被覆盖,因为Swift实现扩展的方式是使用静态分派,这意味着在编译时就可以解决。
阅读https://www.raizlabs.com/dev/2016/12/swift-method-dispatch/
好的,如果您的目标是编译代码,那么上面的代码实际上可以使用一些技巧进行编译。
首先,由于编译器声明我们不能覆盖扩展中的non-objc
声明,因此我们必须使要实现的方法成为@objc
方法。 该解决方法使该方法成为动态调度。 在运行时解决!
可是等等! 它运行正常吗?
啊,它在运行时有效!
我们快乐,可以实现子类中最重要的扩展! 但是有局限性。
使用@objc
意味着您的协议要求签名应与@objc
兼容。 如果您根据与@objc
不兼容的类型提出了要求,该怎么@objc
? 当然,您不能做太多事。 局限性令人恐惧!
让我们看看另一种方法。
自我约束协议扩展
使用此方法,您不需要向@objc
公开任何内容,因为此解决方法是完全Swift的。 但是,让我给您一个线索,这不适用于动态调度。 这样可以编译,但是如果您调用隐藏在其超类类型下的方法,则代码将存在错误。
是的,它可以正确编译。 但是它在运行时有效吗?
如您在Debug输出中所见。 当我们在隐藏在UIView
下的UIStackView
中调用x()
时,就好像我们@objc
上面使用@objc
。 那是因为s
在编译时解析为使用where Self: UIView
实现来调用x()
。
结论
如果您的实现应该动态地分派,则不得使用此override
来与协议扩展一起使用。 您总是有机会使用@objc
及其局限性,或者可以使用constrained protocol extension
,而@objc
担心隐藏在客户端代码中的错误。 明智的朋友。
PS:我已经在此库ViewDSL中实现了@objc
版本