简体   繁体   English

无法覆盖另一个模块swift中类扩展中声明的open方法

[英]Cannot override open method declared in class extension in another module swift

I have a class extension declared in another module (using pods) like this. 我在另一个模块(使用pod)中声明了类扩展。

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

And when I try to override this method in subclass inside my current project module 当我尝试在当前项目模块中的子类中重写此方法时

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

I get an error: 我收到一个错误:

Overriding non-open instance method outside of its defining module 覆盖其定义模块之外的非打开实例方法

despite the method is actually marked as open 尽管该方法实际上标记为开放

As a workaround I declared another class inside same module where extension is declared and overrided desired method there 作为一种解决方法,我在同一模块中声明了另一个类,其中声明了扩展并在那里覆盖了所需的方法

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

and set this class as super class for my class in main module 并在主模块中将此类设置为我的类的超类

class ConcreteView : CustomView

so only after this I was able to override the method. 所以只有在此之后我才能覆盖该方法。

It really looks like a bug in swift3 but maybe I've omitted some understanding of why it works in that way? 它看起来真的像swift3中的一个错误,但也许我已经省略了为什么它以这种方式工作的一些理解?

Short answer: The doStuff method in 简答: doStuff方法

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

has an effective access level "public" because the extension is marked public. 具有有效的访问级别“公共”,因为扩展名标记为公共。 Therefore it cannot be overridden in a subclass. 因此,它不能在子类中重写。

Note that Xcode warns 请注意,Xcode警告

warning: declaring instance method in PUBLIC extension 警告:在PUBLIC扩展中声明实例方法

and the warning text should be (see below) 并且警告文本应该是 (见下文)

warning: declaring OPEN instance method in PUBLIC extension 警告:在PUBLIC扩展中声明OPEN实例方法

To solve the problem, remove the public access modifier of the extension: 要解决此问题,请删除扩展的public访问修饰符:

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

Now the extension has the access level "open" (inherited from open class UIView ) and the effective access level of doStuff is "open" and it can be subclassed. 现在扩展的访问级别为“open”(继承自open class UIView ), doStuff的有效访问级别为“open”,并且可以进行子类化。

Longer answer: 更长的回答:

Access Control in the Swift reference states that Swift参考中的访问控制说明了这一点

... you can mark an extension with an explicit access-level modifier ... to set a new default access level for all members defined within the extension. ...您可以使用显式访问级别修饰符标记扩展名...为​​扩展名中定义的所有成员设置新的默认访问级别。 This new default can still be overridden within the extension for individual type members. 仍可以在单个类型成员的扩展中覆盖此新默认值。

but actually you can only restrict type members within the extension to the same or a lower access. 但实际上,您只能将扩展中的类型成员限制为相同或较低的访问权限。 Unfortunately, I could not find a definite reference for this fact in the documentation. 不幸的是,我在文档中找不到这个事实的明确参考。

SE-0117 Allow distinguishing between public access and public overridability states that SE-0117允许区分公共访问和公共覆盖状态

For example, the true access level of a type member is computed as the minimum of the true access level of the type and the declared access level of the member. 例如,类型成员的真实访问级别计算为类型的真实访问级别和成员的声明访问级别的最小值。 If the class is public but the member is open, the true access level is public. 如果该类是公共的但成员是开放的,则真正的访问级别是公共的。

but does not explain how this applies to extensions. 但没有解释这如何适用于扩展。

The check can be seen in the compiler source code TypeCheckAttr.cpp . 检查可以在编译器源代码TypeCheckAttr.cpp中看到 If the access level of an item is larger then the access level of the containing extension then the diag::access_control_ext_member_more diagnostic message is emitted: 如果项的访问级别大于包含扩展的访问级别,则发出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))

Note that the "open" level is missing in the selection, and that is why it is missing in 请注意,选择中缺少“打开”级别,这就是它缺失的原因

warning: declaring instance method in PUBLIC extension 警告:在PUBLIC扩展中声明实例方法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM