Cannot override public method declared in class extension in another swift module

I have a class extension declared in another module (using containers) like this.

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

And when I try to override this method in a subclass inside my current project module

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

I get an error message:

Overriding non-open instance methods outside its defining module

even though the method is indeed marked as open

As a workaround, I declared another class inside the same module where the extension was declared and redefined the desired method there

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

and set this class as a superclass for my class in the main module

 class ConcreteView : CustomView 

so only after that I was able to override the method.

It really looks like a bug in swift3, but maybe I omitted some idea of โ€‹โ€‹why it works this way?

+6
source share
1 answer

Short answer: doStuff method

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

has an effective access level of "public" because the extension is a marked publication. Therefore, it cannot be overridden in a subclass.

Please note that Xcode warns

warning: instance method declaration in the PUBLIC extension

and the warning text should be (see below)

warning: declaring an OPEN instance method in a PUBLIC extension

To solve the problem, remove the public extension access public :

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

Now the extension has an โ€œopenโ€ access level (inherited from the open class UIView ) and the open class UIView effective access doStuff is โ€œopenโ€ and can be a subclass.

Longer answer:

Access control in swift link what

... you can mark the extension with an explicit access level modifier ... to set a new default access level for all members defined in the extension. This new default value can still be overridden in the extension for individual type members.

but in fact you can only restrict type members in the extension to the same or lower access. Unfortunately, I could not find a specific link for this fact in the documentation.

SE-0117 Allow to distinguish between open access and public revaluation of what

For example, the true access level of a member of a type calculates at least the true level of access to 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 relates to extensions.

Verification can be seen in the source code of the TypeCheckAttr.cpp compiler. If the access level of an item is greater than the access level containing the extension, then diag::access_control_ext_member_more displays a diagnostic message:

 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)) 

Please note that there is no "open" level in the selection, so it is not in

warning: instance method declaration in the PUBLIC extension

+9
source

Source: https://habr.com/ru/post/1012918/


All Articles