"Cannot inherit from non-open class" swift - swift

As of Xcode 8 beta 6 I now get the compile error "Cannot inherit from non-open class (Class)" outside of its defining module"
The class I was inheriting from was part of a separate Swift framework but my project compiled for Xcode 8 beta 5. What do I need to change to get my project to compile again?

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.

The class you inherit from needs to be defined as open instead of public.
A bit more context on the changes to access control in Swift 3:
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 or default access modifier.
public: symbol visible outside the current module.
open: for class or function to be subclassed or overridden outside the current module.

I had this error even after marking the class as open (on Xcode 14.1). The fix was a clean (Cmd + Shift + K) and rebuild.

Related

Swift 3 overriding non-open var outside of its defining module

I converted my swift 2 code into swift 3. Then I'm getting this error. Can anyone help me on this?
open override var formatKey: String { //overriding non-open var outside of its defining module
get {
if customFormatKey != nil {
return customFormatKey!
}
return String(describing: type(of: self)).components(separatedBy: ".").last!
}
}
According to the Access Control section of The Swift Programming Language:
Open access applies only to classes and class members, and it differs
from public access as follows:
Classes with public access, or any more restrictive access level, can
be subclassed only within the module where they’re defined.
Class members with public access, or any more restrictive access
level, can be overridden by subclasses only within the module where
they’re defined.
Open classes can be subclassed within the module where they’re
defined, and within any module that imports the module where they’re
defined.
Open class members can be overridden by subclasses within the module
where they’re defined, and within any module that imports the module
where they’re defined.
open in Swift 3 and later is the equivalent of public in Swift 2. For more information, see Swift Evolution proposal SE-0117.
To fix this, change the original definition of formatKey from public to open, and override using override var formatKey: String { ....
I did face with the same issue, then you can try to search all project - include pods/ folder - to make sure this formatKey is not public var somewhere in your project.

How to get application "namespace" in Swift implicitly?

Short version:
Assuming I have an app called MyApp. In some situation I have a duplicate class name so that one is MyClass where the other is MyApp.MyClass. How can I call MyApp.MyClass having MyApp constant (do not need to change the code if I change the app name).
Why and what happened (long version):
So assume we are in this MyApp application having following code (the real one is way way longer and used allover the app):
class MyClass {
}
class SomeOtherClass {
class MyClass {
}
func findMyClass(fromMyClass: MyApp.MyClass) -> MyClass {
...
}
}
Because there are two classes called MyClass in inner scope we need to call MyApp.MyClass to get the outer one which is all good.
But it seems a bit silly when MyApp changes which is my case.
Why did it change? I actually added a new target by duplicating the original one because I wanted to have some extra and some different settings (pretty standard procedure). So I renamed the new one to have MyApp-dev where I then got an error Use of undeclared type 'MyApp'.
So is there a keyword that can replace MyApp?
My current solution is to define a typealias on file scope that is then used inside the class to replace MyApp. The problem is that the method is not private so the typealias may not be private either which means I just have an extra name defined globally in the project.
EDIT:
Also there is a setting in Xcode build settings called Product Module Name which may be overridden to explicit naming which fixes the issue. Still this not really a good general solution; I can see cases where you might reuse the same code in multiple modules (creating libraries) which has the same issue. This would still meant that code would need to be fixed for each of these modules.

Access class in different file

I'm still a newbie to swift and I can't get a clear answer on a couple things.
So far I've just been using a single file in playgrounds.
If I want to use more files, how can I access data (variables and functions) from classes created there in my main file that controls the view?
From what I understand having multiple files would just be for convenience so I don't have could to write it again.
(Also on the side) what does it mean when a function has private, public or just 'func'?
I'm using swift 3 playgrounds
Thanks
Making things public will make them importable from other modules. Making it private will make it only accessible by methods within its containing scope (encapsulation). For code that lives at the top level, this scope is the entire .swift file it lives in. Without either access modifier (just bare “func”), your thing will default to internal, which means it is accessible from any other code within the same module, but not by code in a different module.
A special case is the fileprivate modifier which restricts access to the .swift file the code lives in. For code that does not live in a class or struct, this does the exact same thing as private. Some Swift designers discourage use of this modifier, and it may be removed in future versions of Swift.
There is a fifth access modifier in Swift, open, which does the exact same thing as public, except it also allows subclassing, and only applies to classes. This one is rarely used, but useful for certain library interfaces.
To import all the public symbols in a module, use
import Module
To import a single public symbol, use
import var Module.variable
import func Module.function
import struct Module.structure
import class Module.class
...

Using of "open" and "public"

I already read the documentation about the new modifiers "open" and "fileprivate". But there are two things that I don't understand:
Why is it not possible to declare protocols or extensions also as "open"? And does it mean that it's not possible to use these things outside a module?
If I don't want to build my classes for a module but an common app, should I declare my classes and methods as "open" anyway or is it good practice to keep them only "public"?
As this answer says:
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.
I think the answer to your first question, is that you can't override or subclass a protocol or extension. Thus, there is no use for such things to be open because public already makes them accessible outside of a module.
For your second question, I would say that you should only declare your own classes as open if you plan on overriding or subclassing. Otherwise you are allowing unnecessary access to these items. Most of the time public should suit your needs.
Edit:
As #Alex points out, I don't think there are many downsides to allowing this "extra access". The only thing I can think of is if you just wanted to protect your classes from your future self, but that may or may not be applicable. Thus, if this is not the case, there shouldn't be much harm in setting them as open by default.
open is for another module, for example in we use it in unit test or in cocoa pods, you can inherit from a pod (if it's: open class somePod {...}) or override some function (if it's: open func someFunctionInPod{...}) in your project.

What is the 'open' keyword in Swift?

The ObjectiveC.swift file from the standard library contains the following few lines of code around line 228:
extension NSObject : Equatable, Hashable {
/// ...
open var hashValue: Int {
return hash
}
}
What does open var mean in this context, or what is the open keyword in general?
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.
Read open as
open for inheritance in other modules
I repeat open for inheritance in other modules.
So an open class is open for subclassing in other modules that include the defining module. Open vars and functions are open for overriding in other modules. Its the least restrictive access level. It is as good as public access except that something that is public is closed for inheritance in other modules.
From Apple Docs:
Open access applies only to classes and class members, and it differs from public access as follows:
Classes with public access, or any more restrictive access level, can
be subclassed only within the module where they’re defined.
Class members with public access, or any more restrictive access level, can
be overridden by subclasses only within the module where they’re
defined.
Open classes can be subclassed within the module where they’re defined, and within any module that imports the module where
they’re defined.
Open class members can be overridden by subclasses
within the module where they’re defined, and within any module that
imports the module where they’re defined.
Open is an access level, was introduced to impose limitations on class inheritance on Swift.
This means that the open access level can only be applied to classes and class members.
In Classes
An open class can be subclassed in the module it is defined in and in modules that import the module in which the class is defined.
In Class members
The same applies to class members. An open method can be overridden by subclasses in the module it is defined in and in modules that import the module in which the method is defined.
THE NEED FOR THIS UPDATE
Some classes of libraries and frameworks are not designed to be subclassed and doing so may result in unexpected behavior. Native Apple library also won't allow overriding the same methods and classes,
So after this addition they will apply public and private access levels accordingly.
For more details have look at Apple Documentation on Access Control
open come to play when dealing with multiple modules.
open class is accessible and subclassable outside of the defining module. An open class member is accessible and overridable outside of the defining module.
open is only for another module for example: cocoa pods, or unit test, we can inherit or override