Cannot inherit from non-open class swift
Found the answer myself.
In Swift 3 you can now mark a class as open
instead of public
this allows files outside of the module to subclass that class.
Simply replace public
in your module class with open
.
Reference here.
Xcode 8: Cannot inherit from non-open class
Short answer:
To be able to subclass it, the base class WDBaseViewController
needs to be defined as open
instead of public
in the framework you are using.
open class WDBaseViewController {
...
}
If it’s an internal framework you can do it yourself, otherwise you will have to wait for the author to support Swift 3.
Long answer:
Swift 3 is bringing significant changes to access control.
Swift 2 only had 3 access levels:
private
: entities are available only from within the source file where they are defined.internal
: entities are available to the entire module that includes the definition.public
: entities are intended for use as API, and can be accessed by any file that imports the module.
Swift 3 is adding 2 more access levels (open
and fileprivate
) and changing the meaning of private
:
private
: symbol visible within the current declaration only.fileprivate
: symbol visible within the current file.internal
: symbol visible within the current module.public
: symbol visible outside the current module.open
: for class or function to be subclassed or overridden outside the current module.
What is the 'open' keyword in Swift?
open
is a new access level in Swift 3, introduced with the implementation
of
- SE-0117 Allow distinguishing between public access and public overridability
It is available with the Swift 3 snapshot from August 7, 2016,
and with Xcode 8 beta 6.
In short:
- An
open
class is accessible and subclassable outside of the
defining module. Anopen
class member is accessible and
overridable outside of the defining module. - A
public
class is accessible but not subclassable outside of the
defining module. Apublic
class member is accessible but
not overridable outside of the defining module.
So open
is what public
used to be in previous
Swift releases and the access of public
has been restricted.
Or, as Chris Lattner puts it in
SE-0177: Allow distinguishing between public access and public overridability:
“open” is now simply “more public than public”, providing a very simple and clean model.
In your example, open var hashValue
is a property which is accessible and can be overridden in NSObject
subclasses.
For more examples and details, have a look at SE-0117.
Protocols can inherit from classes?
It's not really inheriting the protocol from that class. That syntax is saying that the protocol B
can only be conformed to, by A
or subclasses of A
.
Here are some examples:
class C : A {}
class D {}
extension A : B {} // works
// or
// extension C : B {} // works
extension D : B {} // error
Override property declared in framework
You generally cannot override with a stored property. In this case it's a bit tricker, because the value is really just a default (since this is var
). Generally you would override with a computed property:
private var _someProperty: String = "Sunday"
override var someProperty: String { get { _someProperty }
set { _someProperty = newValue } }
Or set the value in the initializer:
override init() {
super.init()
someProperty = "Sunday"
}
Does the initializer of an `open` class need to be open as well?
From SE-0117 Allow distinguishing between public access and public overridability:
Initializers do not participate in open checking; they cannot be declared open, and there are no restrictions on providing an initializer that has the same signature as an initializer in the superclass.
You need not and you cannot declare a init method as open:
open class OpenClass {
open init() { // error: only classes and overridable class members can be declared 'open'; use 'public'
}
}
The default access level for all members of a class (properties
and methods) is internal, that applies to open classes as well.
Cannot override open method declared in class extension in another module swift
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 thediag::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
Related Topics
What Is 'Where Self' in Protocol Extension
Swift Anyobject Is Not Convertible to String/Int
Alternate Approach to Inheritance for Swift Structs
How to Concatenate Optional Swift Strings
Binary Operator '===' Cannot Be Applied to Operands of Type 'Any' and 'Uibarbuttonitem!'
How to Convert a Swift String to Cfstring
Swift Codable Decode Manually Optional Variable
Can a Swift Property Wrapper Reference the Owner of the Property Its Wrapping
Binary Operator '+' Cannot Be Applied to Two 'T' Operands
How to Make Apple Sign in Revoke Token Post Request
How to Get All Days in Current Week in Swift
Scenekit - Scntext Centering Incorrectly
How to Get User Input in Apple's Swift Language in a Command Line Tool
How to Reload a UI View's Content Swift