"Cannot Inherit from Non-Open Class" Swift

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. An open class member is accessible and
    overridable outside of the defining module.
  • A public class is accessible but not subclassable outside of the
    defining module. A public 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 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



Related Topics



Leave a reply



Submit