I have a class extension declared in another module (using pods) like this.
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?
Short answer: The doStuff
method in
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
warning: declaring instance method in PUBLIC extension
and the warning text should be (see below)
warning: declaring OPEN instance method in PUBLIC extension
To solve the problem, remove the public
access modifier of the extension:
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.
Longer answer:
Access Control in the Swift reference states that
... 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
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.
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:
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With