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 inhas an effective access level "public" because the extension is marked public. Therefore it cannot be overridden in a subclass.
Note that Xcode warns
and the warning text should be (see below)
To solve the problem, remove the
public
access modifier of the extension:Now the extension has the access level "open" (inherited from
open class UIView
) and the effective access level ofdoStuff
is "open" and it can be subclassed.Longer answer:
Access Control in the Swift reference states that
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
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:Note that the "open" level is missing in the selection, and that is why it is missing in