无法重写在另一个模块swift中的类扩展中声明的打开方法

我有一个类扩展声明在另一个模块(使用豆荚)这样的。

public extension UIView { open func doStuff() {...} } 

当我尝试在我的当前项目模块中的子类中重写此方法

 class ConcreteView : UIView { override open func doStuff() {...} } 

我收到一个错误:

在其定义模块之外重写非开放实例方法

尽pipe方法实际上标记为打开

作为一种解决方法,我声明了另一个类在同一个模块中扩展声明和覆盖所需的方法

 public class CustomView: UIView { override open func doStuff() {...} } 

并将该类设置为主模块中的我的类的超类

 class ConcreteView : CustomView 

所以只有在这之后我才能够重写这个方法。

它看起来像swift中的一个bug,但也许我忽略了为什么它以这种方式工作的一些理解?

简短的回答:中doStuff方法

 public extension UIView { open func doStuff() {...} } 

有一个有效的访问级别“公共”,因为该扩展标记为公开的。 因此它不能在一个子类中重写。

请注意,Xcode警告

警告:在PUBLIC扩展中声明实例方法

和警告文本应该是 (见下文)

警告:在PUBLIC扩展中声明OPEN实例方法

要解决该问题,请删除扩展的public访问修饰符:

 extension UIView { open func doStuff() {...} } 

现在扩展名的访问级别为“open”(inheritance自open class UIView ), doStuff的有效访问级别为“open”,可以进行子类化。

较长的答案:

访问控制在Swift参考中指出

…您可以使用明确的访问级别修饰符标记扩展…为扩展中定义的所有成员设置新的默认访问级别。 这个新的默认值仍然可以在个别types成员的扩展名中被覆盖。

但实际上只能将扩展中的types成员限制为相同或较低的访问权限。 不幸的是,在文档中我找不到这个事实的明确参考。

SE-0117允许区分公共访问和公共可重写状态

例如,types成员的真实访问级别被计算为types的真实访问级别和成员的已声明访问级别的最小值。 如果class级是公开的,但是会员是开放的,则真实的访问级别是公开的。

但并没有解释如何适用于扩展。

该检查可以在编译器源代码TypeCheckAttr.cpp中看到 。 如果一个项目的访问级别大于包含扩展的访问级别,则会发出diag::access_control_ext_member_more诊断消息:

 WARNING(access_control_ext_member_more,none, "declaring %select{PRIVATE|a fileprivate|an internal|a public}0 %1 in " "%select{a private|a fileprivate|an internal|PUBLIC}2 extension", (Accessibility, DescriptiveDeclKind, Accessibility)) 

请注意,select中缺less“打开”级别,这就是为什么它缺less

警告:在PUBLIC扩展中声明实例方法