I'm confused about the internal and private access modifier.
The docs says:
“Internal access enables entities to be used within any source file
from their defining module, but not in any source file outside of that
module. You typically use internal access when defining an app’s or a
framework’s internal structure.”
How I thought it was, was that with internal you can access everything if you are in your own app. But this is not true, because when I have a viewcontroller what is default internal and I'm having a internal function on that viewcontroller I can't access this from another file in another group (You create these in xCode).
What I tried was having a ViewController that has a method foo in group A then in group B I created a ViewController like this:
let vc: FakeViewController = FakeViewController()
vc.foo()
So is internal restricted to the same group? Or I'm I interpreting it wrong?
Is it useful that in a viewcontroller you create private methods and vars/lets?
#user1007522 Could you post the entire source code for FakeViewController? You should have access to foo() from your vc variable. If you do not, I suspect something else is in play here.
I found the following definitions much easier to understand (copied from UseYourLoaf - Swift 4 Access Levels)
The Five Access Levels of Swift 3/4
Swift 3 has five access levels that control from which source file or module you can access something. In order from most open to most restricted:
open you can access open classes and class members from any source file in the defining module or any module that imports that module. You can subclass an open class or override an open class member both within their defining module and any module that imports that module.
public allows the same access as open - any source file in any module - but has more restrictive subclassing and overriding. You can only subclass a public class within the same module. A public class member can only be overriden by subclasses in the same module. This is important if you are writing a framework. If you want a user of that framework to be able to subclass a class or override a method you must make it open.
internal allows use from any source file in the defining module but not from outside that module. This is generally the default access level.
fileprivate allows use only within the defining source file.
private Swift 4: allows use only from the enclosing declaration and new in Swift 4, to any extensions of that declaration in the same source file Swift 3: allows use only from the enclosing declaration.
Suppose you have 3 different view controller source files A, B, C
then
In Private:- If Intancses in A are Private than only A's Methods can use them
In Internal :- IF A is as Internal than B and C can easily use them.
Here is an example:
Thanks
Internal access restricts access to the files within a singular application or framework.
Private restricts access to the individual source file that your object is created in.
See this link for a more in-depth explanation.
Overall, if your "Group A" and "Group B" are in the same application or framework, you should be able to access the methods from each, assuming the viewController allows internal access.
My understanding is that private won't allow the variable from being accessed from outside that class. However, there are times, like with gesture recognizers, you can't make them private because they are needed behind the scenes. Marking them as "internal" lets them be accessed from within other functions, but not called directly.
Mostly I use internal to keep my code organized, so I know that's not a public facing function but it can still be used.
Related
I have a DataManager class and it has some relevant functions and variables. For example,
Class DataManager: NSObject {
func doSomething()
func doSomethingAgain()
}
I move few method to an extension of DataManager. I made the extension as fileprivate cause I don't want to expose those function to other classes. For example,
Class DataManager: NSObject {
func doSomething()
}
fileprivate extension DataManager {
func doSomethingAgain()
}
Till now everything was fine, now the problem I am facing is when I am moving that extension to a different file that time fileprivate won't work. So what should be the protection level in that case. Hope you understood my intension.
The protection level should be internal (which is the default). It will then be available to everything in the module.
If you want to constrain access to a smaller number of classes, then you need to put those classes in their own module. Those are only access levels that Swift has.
The tightest access mode you can work with is the internal which is default in Swift.
Taking from https://docs.swift.org/swift-book/LanguageGuide/AccessControl.html :
"Swift provides five different access levels for entities within your code. These access levels are relative to the source file in which an entity is defined, and also relative to the module that source file belongs to.
Open access and public access enable entities to be used within any source file from their defining module, and also in a source file from another module that imports the defining module. You typically use open or public access when specifying the public interface to a framework. The difference between open and public access is described below.
Internal access enables entities to be used within any source file from their defining module, but not in any source file outside of that module. You typically use internal access when defining an app’s or a framework’s internal structure.
File-private access restricts the use of an entity to its own defining source file. Use file-private access to hide the implementation details of a specific piece of functionality when those details are used within an entire file.
Private access restricts the use of an entity to the enclosing declaration, and to extensions of that declaration that are in the same file. Use private access to hide the implementation details of a specific piece of functionality when those details are used only within a single declaration."
Edit: So far it looks like the answer to my question is, "You can't do that in Swift." I currently have a solution whereby the subclass names are listed in an array and I loop around and instantiate them to trigger the process I'm describing below. If this is the best that can be done, I'll switch it to a plist so that least it's externally defined. Another option would be to scan a directory and load all files found, then I would just need to make sure the compiler output for certain classes is put into that directory...
I'm looking for a way to do something that I've done in C++ a few times. Essentially, I want to build a series of concrete classes that implement a particular protocol, and I want to those classes to automatically register themselves such that I can obtain a list of all such classes. It's a classic Prototype pattern (see GoF book) with a twist.
Here's my approach in C++; perhaps you can give me some ideas for how to do this in Swift 4? (This code is grossly simplified, but it should demonstrate the technique.)
class Base {
private:
static set<Base*> allClasses;
Base(Base &); // never defined
protected:
Base() {
allClasses.put(this);
}
public:
static set<Base*> getAllClasses();
virtual Base* clone() = 0;
};
As you can see, every time a subclass is instantiated, a pointer to the object will be added to the static Base::allClasses by the base class constructor.
This means every class inherited from Base can follow a simple pattern and it will be registered in Base::allClasses. My application can then retrieve the list of registered objects and manipulate them as required (clone new ones, call getter/setter methods, etc).
class Derived: public Base {
private:
static Derived global; // force default constructor call
Derived() {
// initialize the properties...
}
Derived(Derived &d) {
// whatever is needed for cloning...
}
public:
virtual Derived* clone() {
return new Derived(this);
}
};
My main application can retrieve the list of objects and use it to create new objects of classes that it knows nothing about. The base class could have a getName() method that the application uses to populate a menu; now the menu automatically updates when new subclasses are created with no code changes anywhere else in the application. This is a very powerful pattern in terms of producing extensible, loosely coupled code...
I want to do something similar in Swift. However, it looks like Swift is similar to Java, in that it has some kind of runtime loader and the subclasses in this scheme (such as Derived) are not loaded because they're never referenced. And if they're not loaded, then the global variable never triggers the constructor call and the object isn't registered with the base class. Breakpoints in the subclass constructor shows that it's not being invoked.
Is there a way to do the above? My goal is to be able to add a new subclass and have the application automatically pick up the fact that the class exists without me having to edit a plist file or doing anything other than writing the code and building the app.
Thanks for reading this far — I'm sure this is a bit of a tricky question to comprehend (I've had difficulty in the past explaining it!).
I'm answering my own question; maybe it'll help someone else.
My goal is to auto initialize subclasses such that they can register with a central authority and allow the application to retrieve a list of all such classes. As I put in my edited question, above, there doesn't appear to be a way to do this in Swift. I have confirmed this now.
I've tried a bunch of different techniques and nothing seems to work. My goal was to be able to add a .swift file with a class in it and rebuild, and have everything automagically know about the new class. I will be doing this a little differently, though.
I now plan to put all subclasses that need to be initialized this way into a particular directory in my application bundle, then my AppDelegate (or similar class) will be responsible for invoking a method that scans the directory using the filenames as the class names, and instantiating each one, thus building the list of "registered" subclasses.
When I have this working, I'll come back and post the code here (or in a GitHub project and link to it).
Same boat. So far the solution I've found is to list classes manually, but not as an array of strings (which is error-prone). An a array of classes such as this does the job:
class AClass {
class var subclasses: [AClass.Type] {
return [BClass.self, CClass.self, DClass.self]
}
}
As a bonus, this approach allows me to handle trees of classes, simply by overriding subclasses in each subclass.
Swift offers 5 access modifiers: open, public, internal, fileprivate and private.
Of what I know about these specifiers, (mainly from link & link_2)
open means classes and class members can be subclassed and overridden both within and outside the defining module (target).
fileprivate restricts the use of an entity to its defining source file. Basically accessible by multiple classes within a single file.
private restricts the use of an entity to its enclosing declaration.
Now, public and internal seems pretty much the same to me :-
public means classes and class members can only be subclassed and overridden within the defining module (target).
internal enables an entity to be used within the defining module (target). Also, this happens to be the default specifier if nothing else is mentioned. We would typically use internal access when defining an app’s or a framework’s internal structure.
So basically how do public and internal differ?
This is my first Question here, so if I have missed out any details, please let me know. Thanks in advance.
Whatever you marked as public can be use within your app and outside of you app(module). If you marked something as internal that can only be used within your app(module). This is very helpful when your developing a library (framework) , you can use internal to hide library structure.
And Public members of A.swift and B.swift are available to C.swift and D.swift. The only restriction is that classes can't be subclassed (they would need to be open.)
- My answer base on #Keaz & #Alexander.
From Access Control manual:
Open access and public access enable entities to be used within any
source file from their defining module, and also in a source file from
another module that imports the defining module. You typically use
open or public access when specifying the public interface to a
framework. The difference between open and public access is described
below.
Internal access enables entities to be used within any source
file from their defining module, but not in any source file outside of
that module. You typically use internal access when defining an app’s
or a framework’s internal structure.
Difference is in visibility to other modules.
EDIT to answer #iCode comment:
You don't need all of them.
For simplest small single-dev application just using default internal will be enough.
If you will need to do it right you may add fileprivate/private accessors to hide some implementation.
If you're developing large app and want to separate code into modules, or if you're developing library you will need to use public/open to create inter-module interface.
I have some swift extensions I want to across projects.
I'd like to avoid category pollution though, unless those extensions are requested.
Is it possible to write them so that they only apply if I've done a certain import, like:
import MySwiftExtensions
// Use custom extensions
let x = [1,3,5,7].average()
let y = [1,3,5,7].firstWhere { $0 > 3 }
let z = "campervan".make1337()
I could write these as static methods wrapped in a single letter class (eg: ø.average([1,3,5,7]), like lodash) to achieve the same thing but sometimes you get much more concise usage from instance methods.
You wrote:
I have some swift extensions I want to across projects...
When I have code that I want to use across projects I create a separate framework to hold that code. Then, when I want to use that code in a new project, I embed the framework in that project. Or, for development purposes, I create a workspace that includes the project and the framework. That allows me to work on both at the same time, and then only embed the framework in the final product when it is time to export it.
Once the framework is either embedded or in the same workspace, then you should be able to import it into any individual file in your project with:
import MySwiftExtensions
Any file that does not have the import statement will not have access to the extensions.
EDIT:
Here is a link to a blog that describes how to create a Cocoa Touch Framework. And here is another link that describes in detail how to use workspaces to use frameworks in development projects.
I would like to focus attention on what you reported: "..only apply if I've done a certain import.."
It would also mean you want these extensions can be applyed only to a specific class
As reported in this interesting Apple blog chapter and in the official Apple doc you can handle the "Access Control" of your extension
You can extend a class, structure, or enumeration in any access
context in which the class, structure, or enumeration is available.
Any type members added in an extension have the same default access
level as type members declared in the original type being extended. If
you extend a public or internal type, any new type members you add
will have a default access level of internal. If you extend a private
type, any new type members you add will have a default access level of
private.
Alternatively, you can mark an extension with an explicit access level
modifier (for example, private extension) 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.
/* no access level modifier: default access level will be 'internal' */
extension UIViewSubClass
{
// default access level used: internal
var helloWorld : String {
get {
return "helloWorld"
}
}
}
// modify default access level to public
public extension UIViewSubClass
{
// default access level used: public
var helloWorld : String {
get {
return "helloWorld"
}
}
}
The members of extensions marked private are available within the file where they’re defined, and are not available outside that file. Outside the file where the private extension members were defined, any attempt to use them results in an error, and auto-complete wouldn’t even list them
// modify default access level to private
private extension UIViewSubClass
{
var helloWorld : String {
get {
return "helloWorld"
}
}
}
I don't believe you can do what you want per se, but I've used the following approach to provide functionality to only the specific class that implements an interface:
protocol ExampleProtocol {
}
extension ExampleProtocol where Self: UIViewController{
// extend what you need to here
}
How can I make protected (like in ruby) variable or function in Swift? I know Swift has only 3 levels but nonetheless is it possible?
Access Levels
Swift provides three different access levels for entities within your
code. These access levels are relative to the source file in which an
entity is defined, and also relative to the module that source file
belongs to.
Public access enables entities to be used within any source file from
their defining module, and also in a source file from another module
that imports the defining module. You typically use public access when
specifying the public interface to a framework.
Internal access
enables entities to be used within any source file from their defining
module, but not in any source file outside of that module. You
typically use internal access when defining an app’s or a framework’s
internal structure.
Private access restricts the use of an entity to
its own defining source file. Use private access to hide the
implementation details of a specific piece of functionality.
Public
access is the highest (least restrictive) access level and private
access is the lowest (or most restrictive) access level
Currently I see only one solution - write parent class with private modifier and children class in single file but it's kind of painful.
Swift prefers to not use protected. You can read the reasons here Access Control and protected
In contrast, protected conflates access with inheritance, adding an entirely new control axis to reason about. It doesn’t actually offer any real protection, since a subclass can always expose “protected” API through a new public method or property. It doesn’t offer additional optimization opportunities either, since new overrides can come from anywhere. And it’s unnecessarily restrictive — it allows subclasses, but not any of the subclass’s helpers, to access something.
In Ruby's point of view, it may be important. However in Swift, neither it is useless, nor it is a matter of the language.
Swift language is primarily based on modules when it comes to access levels. It even has public private(set) variables, which is much needed in Objective-C (causes boilerplate).
There's no equivalent to protected in Swift where only subclasses have access to the method. Personally, I don't miss it.
In Swift (as Objective-C) there is far less emphasis on subclassing than other languages. If you find you have a set of methods that you want to be protected, it is probably better to factor them out as a delegate.
Swift 3.0 not cantains protected modifier. In our sdk we use internal(set) modifier that approve set operation only in sdk project.
private var _authorized : Bool = false
public internal(set) var authorized : Bool
{
get
{
return _authorized;
}
set
{
_authorized = newValue
}
}