Does Swift have access modifiers?
Asked Answered
P

16

293

In Objective-C instance data can be public, protected or private. For example:

@interface Foo : NSObject
{
  @public
    int x;
  @protected:
    int y;
  @private:
    int z;
  }
-(int) apple;
-(int) pear;
-(int) banana;
@end

I haven't found any mention of access modifiers in the Swift reference. Is it possible to limit the visibility of data in Swift?

Pecos answered 2/6, 2014 at 21:52 Comment(2)
Added an answer updated for final version of Xcode 6.1.1Selfpronouncing
Swift 4 updated answer.Physiologist
T
453

As of Swift 3.0.1, there are 4 levels of access, described below from the highest (least restrictive) to the lowest (most restrictive).


1. open and public

Enable an entity to be used outside the defining module (target). You typically use open or public access when specifying the public interface to a framework.

However, open access applies only to classes and class members, and it differs from public access as follows:

  • public classes and class members can only be subclassed and overridden within the defining module (target).
  • open classes and class members can be subclassed and overridden both within and outside the defining module (target).

// First.framework – A.swift

open class A {}

// First.framework – B.swift

public class B: A {} // ok

// Second.framework – C.swift

import First

internal class C: A {} // ok

// Second.framework – D.swift

import First

internal class D: B {} // error: B cannot be subclassed

2. internal

Enables an entity to be used within the defining module (target). You typically use internal access when defining an app’s or a framework’s internal structure.

// First.framework – A.swift

internal struct A {}

// First.framework – B.swift

A() // ok

// Second.framework – C.swift

import First

A() // error: A is unavailable

3. fileprivate

Restricts the use of an entity to its defining source file. You typically use fileprivate access to hide the implementation details of a specific piece of functionality when those details are used within an entire file.

// First.framework – A.swift

internal struct A {

    fileprivate static let x: Int

}

A.x // ok

// First.framework – B.swift

A.x // error: x is not available

4. private

Restricts the use of an entity to its enclosing declaration. You typically use private access to hide the implementation details of a specific piece of functionality when those details are used only within a single declaration.

// First.framework – A.swift

internal struct A {

    private static let x: Int

    internal static func doSomethingWithX() {
        x // ok
    }

}

A.x // error: x is unavailable
Tolerate answered 3/6, 2014 at 10:14 Comment(24)
Could someone explain to me why isn't this a big deal?Glassco
I don't know if it is good news, as “protocols” with factories lead to a cleaner design.Dreary
There always are some methods or variables in OOP that should be private or protected. This allows for implementing SOLID design, as big methods are divided to a number of smaller ones, each with its own responsibility, that can be overriden, but only the "main" method should be available for public usage.Tolerate
I asked a swift engineer this question and raised the concerns about safety and how it goes against the philosophy of swift. He said it was a popular request and we should file a report for it. I'm really glad that they confirmed it already!Wortham
Well, with a protocol and a factory you'll have at least 3 types when you need only one. Sometimes it's good, but not always. I don't think that having at least twice the amount of types (a protocol for each class) is alwa6s cleaner. Keep It Stupid Simple.Glassco
For apps, this shouldn't be a big deal because your code will be consumed by no one else but you and your dev team. In that case just prepend "private" members with an underscore(or for hilarity, a really obscure unicode character/emoji) and call it your team's "Best practice". I can see the problem for library and open-source developers though. The good thing is that the only IDE that can compile Swift so far is still in BETA, which means we can hope that we'll get this before the public release.Identification
I indeed had third-party libraries in mind (both open- and closed-source, because now we can create true frameworks for iOS).Tolerate
I, personally don't like solutions like the one with the underscore/special-char leading "private" methods. Even if it is guaranteed that i for myself will be the only person ever having a look at this code, it makes the code more save / less prone to errors cause the compiler will simply prevent you from doing things you should not do. So I think they should get out the "access control mechanisms" as fast as possible, so people wont get used to bad habits.Jonette
@sh4kesbeer: In very few languages are access modifiers a security measure. In dynamic languages like C# or Java you can reflect private members out, and languages like c++ offer zero safety as a rule. Access modifiers are a codified convention with no more real world "prevention" than _method conventions. Access modifiers look cleaner and have various nicer semantics, but either can be called or not from outside code.Ohare
@Ohare If a language has access modifiers, developers (i.e. framework developers) may use them or decide not to do so. In everything-is-public languages, those who want to prevent "unauthorized access", have no other choice than having to implement some twisted security checks to do so. Having those modifiers does no harm, only eases developers' lifes. By the way, it's been 31 years since the introduction of C++, why not move forward?Tolerate
The Xcode 6 beta release notes say: "Access control (public/private members) is not enabled in this seed. (15747445)"Adsorbent
I was really surprised that this didn't work out of the box, but good to hear that it's on the way. I will mark stuff that should be set private with comments for the time being, to be able to easily implement it later.Uvulitis
@Tolerate There's no such thing as "unauthorized access". No human can predict for all time that no one else will ever need to access an internal method of a class. It's the consumer who's in charge of how they want to use code, not the creator. As has been noted, you can always get around it anyway, so just like copy protection it only inconveniences good people.Kerr
@FlorianRachor But if the world doesn't explode in the meantime, maybe that's a sign that you never really needed it in the first place?Kerr
@Kerr Yeou're right, we cannot predict that. Users may even alter the source files, changing protected to public. But it doesn't mean that access modifiers are useless. It's like saying that annotating the return type of a method is useless (if it wasn't for the compiler), because a method can return whatever it wants. Access modifiers are an important part of clean and readable API, just like type annotations.Tolerate
@Kerr Depends on how large your team is. If more then two persons or even two teams are working on the code you need this stuff. Sure you could try and communicate that certain functions are not meant to use public, but in my experience this never works. If it's coded in, I save myself a lot of time and annoying emails.Uvulitis
@Kerr The idea of a public interface is highly valuable. If you intend that all code in a class must reside inside functions that are part of the public API, I think that's quite limiting. On the other hand, having a specified public API allows the implementation to change (including use of private methods) without disrupting consumers. If someone 'needs' to use an internal class method I feel they are misunderstanding the limits of the class' functionality (or are trying to use a buggy class).Fretwork
It's nice that Apple developers still listen to the third-party ones. :)Tolerate
However you can't add a target for a UIController inherited class to invoke a private method in the same class. Which is a big bummer.Mcgehee
Why? When you're giving away your selector it can't private antymore.Tolerate
Is there a way to set a whole bunch of things private at once in Swift, or do you have to write private on every line?Beanie
You have to write it on every line, unfortunately.Tolerate
No "protected" modifier? You've got to be kidding me.Annmaria
@gangelo: No, this is not a joke. Swift Core Team explained the decision in a blog post: developer.apple.com/swift/blog/?id=11 and there was an extensive mailing list discussion on swift-evolution: lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160328/…Tolerate
P
39

Swift 4 / Swift 5

As per mentioned in the Swift Documentation - Access Control, Swift has 5 Access Controls:

  • open and public: can be accessed from their module's entities and any module's entities that imports the defining module.

  • internal: can only be accessed from their module's entities. It is the default access level.

  • fileprivate and private: can only be accessed in limited within a limited scope where you define them.



What is the difference between open and public?

open is the same as public in previous versions of Swift, they allow classes from other modules to use and inherit them, i.e: they can be subclassed from other modules. Also, they allow members from other modules to use and override them. The same logic goes for their modules.

public allow classes from other module to use them, but not to inherit them, i.e: they cannot be subclassed from other modules. Also, they allow members from other modules to use them, but NOT to override them. For their modules, they have the same open's logic (they allow classes to use and inherit them; They allow members to use and override them).


What is the difference between fileprivate and private?

fileprivate can be accessed from the their entire files.

private can only be accessed from their single declaration and to extensions of that declaration that are in the same file; For instance:

// Declaring "A" class that has the two types of "private" and "fileprivate":
class A {
    private var aPrivate: String?
    fileprivate var aFileprivate: String?

    func accessMySelf() {
        // this works fine
        self.aPrivate = ""
        self.aFileprivate = ""
    }
}

// Declaring "B" for checking the abiltiy of accessing "A" class:
class B {
    func accessA() {
        // create an instance of "A" class
        let aObject = A()

        // Error! this is NOT accessable...
        aObject.aPrivate = "I CANNOT set a value for it!"

        // this works fine
        aObject.aFileprivate = "I CAN set a value for it!"
    }
}



What are the differences between Swift 3 and Swift 4 Access Control?

As mentioned in the SE-0169 proposal, the only refinement has been added to Swift 4 is that the private access control scope has been expanded to be accessible from extensions of that declaration in the same file; For instance:

struct MyStruct {
    private let myMessage = "Hello World"
}

extension MyStruct {
    func printMyMessage() {
        print(myMessage)
        // In Swift 3, you will get a compile time error:
        // error: 'myMessage' is inaccessible due to 'private' protection level

        // In Swift 4 it should works fine!
    }
}

So, there is no need to declare myMessage as fileprivate to be accessible in the whole file.

Physiologist answered 26/9, 2016 at 8:25 Comment(0)
K
17

When one talks about making a "private method" in Swift or ObjC (or ruby or java or…) those methods aren't really private. There's no actual access control around them. Any language that offers even a little introspection lets developers get to those values from outside the class if they really want to.

So what we're really talking about here is a way to define a public-facing interface that merely presents the functionality we want it to, and "hides" the rest that we consider "private".

The Swift mechanism for declaring interfaces is the protocol, and it can be used for this purpose.

protocol MyClass {
  var publicProperty:Int {get set}
  func publicMethod(foo:String)->String
}

class MyClassImplementation : MyClass {
  var publicProperty:Int = 5
  var privateProperty:Int = 8

  func publicMethod(foo:String)->String{
    return privateMethod(foo)
  }

  func privateMethod(foo:String)->String{
    return "Hello \(foo)"
  }
}

Remember, protocols are first-class types and can be used anyplace a type can. And, when used this way, they only expose their own interfaces, not those of the implementing type.

Thus, as long as you use MyClass instead of MyClassImplementation in your parameter types, etc. it should all just work:

func breakingAndEntering(foo:MyClass)->String{
  return foo.privateMethod()
  //ERROR: 'MyClass' does not have a member named 'privateMethod'
}

There are some cases of direct assignment where you have to be explicit with type instead of relying on Swift to infer it, but that hardly seems a deal breaker:

var myClass:MyClass = MyClassImplementation()

Using protocols this way is semantic, reasonably concise, and to my eyes looks a lot like the Class Extentions we've been using for this purpose in ObjC.

Kathline answered 13/6, 2014 at 12:51 Comment(4)
If protocols don't allow us to have a default argument, how can I create a public method with optional parameters that still complies with the protocol?Vocabulary
I don't understand what you mean. The following creates a public method with an optional parameter. There doesn't seem to be a problem: gist.github.com/anonymous/17d8d2d25a78644046b6Kathline
For some reason the optional parameter is not working as it should on my project, had already tried something similar to your GitHub example. As we can't set a default parameter on a protocol, I got stuck and ended up asking a question. Thanks for trying to help.Vocabulary
We all know that anything is hackable. We just need some order whats why we need access modifiersAchromatous
D
14

As far as I can tell, there are no keywords 'public', 'private' or 'protected'. This would suggest everything is public.

However Apple may be expecting people to use “protocols” (called interfaces by the rest of the world) and the factory design pattern to hide details of the implementation type.

This is often a good design pattern to use anyway; as it lets you change your implementation class hierarchy, while keeping the logical type system the same.

Dreary answered 3/6, 2014 at 10:4 Comment(4)
This is nice as it also reduces coupling and can make testing easier.Puttyroot
That would work better if there was a way to hide the implementation class of the protocol, but there doesn't seem to be.Chery
Can anyone provide an illustrative example of this pattern?Tnt
Well, this answer was valid in the previous Swift version(s), it seems that it is not valid anymore :) please check my answer.Physiologist
P
12

Using a combination of protocols, closures, and nested/inner classes, it's possible to use something along the lines of the module pattern to hide information in Swift right now. It's not super clean or nice to read but it does work.

Example:

protocol HuhThing {
  var huh: Int { get set }
}

func HuhMaker() -> HuhThing {
   class InnerHuh: HuhThing {
    var innerVal: Int = 0
    var huh: Int {
      get {
        return mysteriousMath(innerVal)
      }

      set {
       innerVal = newValue / 2
      }
    }

    func mysteriousMath(number: Int) -> Int {
      return number * 3 + 2
    }
  }

  return InnerHuh()
}

HuhMaker()
var h = HuhMaker()

h.huh      // 2
h.huh = 32 
h.huh      // 50
h.huh = 39
h.huh      // 59

innerVal and mysteriousMath are hidden here from outside use and attempting to dig your way into the object should result in an error.

I'm only part of the way through my reading of the Swift docs so if there's a flaw here please point it out, would love to know.

Pedro answered 4/6, 2014 at 19:41 Comment(8)
ok, i thought about this solution too, but explain me, why i cannot acces with h.huh.innerVal?Uncounted
Swift is type-safe and the only thing the external world knows about h is that it complies to HuhThing. HuhThing does not include any information about a property called innerVal and so attempting to access it is an error.Pedro
Still accessible :P reflect(h)[0].1.value // 19Identification
Nice find there John - I wasn't aware of reflect. Seems to turn objects into Tuples - is there any official documentation on that function or other metaprogramming stuff in Swift? I took a look through the language guide on iBooks but I'm not seeing it.Pedro
I just found reflect in the headers when browsing for what Mirror was because they keep popping up in autocomplete.Identification
@JohnEstropia I don't think reflection counts. In Java (a more mature language), there are access modifiers, but they don't prevent reflection tricks either.Carnelian
@11684: Note that I do think Dave's method is elegant enough, but he did ask to mention any flaws so I showed that there is still a way to extract hidden classes, methods, and properties.Identification
It would probably be hard to get people to universally agree if this is a flaw or not, but it's definitely worth knowing, so I'm very glad it was pointed out. :)Pedro
F
10

As of Xcode 6 beta 4, Swift has access modifiers. From the release notes:

Swift access control has three access levels:

  • private entities can only be accessed from within the source file where they are defined.
  • internal entities can be accessed anywhere within the target where they are defined.
  • public entities can be accessed from anywhere within the target and from any other context that imports the current target’s module.

The implicit default is internal, so within an application target you can leave access modifiers off except where you want to be more restrictive. In a framework target (e.g. if you're embedding a framework to share code between an app and an sharing or Today view extension), use public to designate API you want to expose to clients of your framework.

Fluidextract answered 21/7, 2014 at 17:15 Comment(1)
Well, this answer was valid in the previous Swift version(s), it seems that it is not valid anymore :) please check my answer.Physiologist
P
6

Swift 3.0 provides five different access controls:

  1. open
  2. public
  3. internal
  4. fileprivate
  5. private

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.

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. Use private access to hide the implementation details of a specific piece of functionality when those details are used only within a single declaration.

Open access is the highest (least restrictive) access level and private access is the lowest (most restrictive) access level.

Default Access Levels

All entities in your code (with a few specific exceptions) have a default access level of internal if you do not specify an explicit access level yourself. As a result, in many cases you do not need to specify an explicit access level in your code.

The release note on the topic:

Classes declared as public can no longer be subclassed outside of their defining module, and methods declared as public can no longer be overridden outside of their defining module. To allow a class to be externally subclassed or a method to be externally overridden, declare them as open, which is a new access level beyond public. Imported Objective-C classes and methods are now all imported as open rather than public. Unit tests that import a module using an @testable import will still be allowed to subclass public or internal classes as well as override public or internal methods. (SE-0117)

More information & details : The Swift Programming Language (Access Control)

Philippines answered 19/9, 2016 at 22:11 Comment(1)
Well, this answer was valid in the previous Swift version(s), it seems that it is not valid anymore :) please check my answer.Physiologist
P
4

In Beta 6, the documentation states that there are three different access modifiers:

  • Public
  • Internal
  • Private

And these three apply to Classes, Protocols, functions and properties.

public var somePublicVariable = 0
internal let someInternalConstant = 0
private func somePrivateFunction() {}

For more, check Access Control.

Peahen answered 3/9, 2014 at 10:52 Comment(2)
There should've been a protected modifier which eases creating classes with greater security.Highness
Well, this answer was valid in the previous Swift version(s), it seems that it is not valid anymore :) please check my answer.Physiologist
U
2

For Swift 1-3:

No, it's not possible. There aren't any private/protected methods and variables at all.

Everything is public.

Update Since Swift 4, it's possible see other answers in this thread

Uncounted answered 2/6, 2014 at 22:21 Comment(4)
This comment is accurate for the current seed.Torrez
For the current seed. It will appear in the future.Torrez
"public" / "protected" / "private" do not currently exist, but you can hide things using closures, protocols, and inner classes - this makes it somewhat like the module pattern used in JavaScript commonly. Please see my sample code on my reply here for an example of how to do this. If I'm mistaken about how it works and my example is incorrect please point that out as I'm still learning too. :)Pedro
It seems that it is not valid anymore :) please check my answer.Physiologist
F
2

Now in beta 4, they've added access modifiers to Swift.

from Xcode 6 beta 4 realese notes:

Swift access control has three access levels:

  • private entities can only be accessed from within the source file where they are defined.
  • internal entities can be accessed anywhere within the target where they are defined.
  • public entities can be accessed from anywhere within the target and from any other context that imports the current target’s module.

By default, most entities in a source file have internal access. This allows application developers to largely ignore access control while allowing framework developers full control over a framework's API.

Foreshore answered 21/7, 2014 at 18:31 Comment(1)
Well, this answer was valid in the previous Swift version(s), it seems that it is not valid anymore :) please check my answer.Physiologist
S
2

Access control mechanisms as introduced in Xcode 6:

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.

Default accecss it internal, and does as such not need to be specified. Also note that the private specifier does not work on the class level, but on the source file level. This means that to get parts of a class really private you need to separate into a file of its own. This also introduces some interesting cases with regards to unit testing...

Another point to me made, which is commented upon in the link above, is that you can't 'upgrade' the access level. If you subclass something, you can restrict it more, but not the other way around.

This last bit also affects functions, tuples and surely other stuff in the way that if i.e. a function uses a private class, then it's not valid to have the function internal or public, as they might not have access to the private class. This results in a compiler warning, and you need to redeclare the function as a private function.

Selfpronouncing answered 8/3, 2015 at 22:52 Comment(1)
Well, this answer was valid in the previous Swift version(s), it seems that it is not valid anymore :) please check my answer.Physiologist
S
2

Swift 3 and 4 brought a lot of change also for the access levels of variables and methods. Swift 3 and 4 now has 4 different access levels, where open/public access is the highest (least restrictive) access level and private access is the lowest (most restrictive) access level:

  • private functions and members can only be accessed from within the scope of the entity itself (struct, class, …) and its extensions (in Swift 3 also the extensions were restricted)
  • fileprivate functions and members can only be accessed from within the source file where they are declared.
  • internal functions and members (which is the default, if you do not explicitly add an access level key word) can be accessed anywhere within the target where they are defined. Thats why the TestTarget doesn't have automatically access to all sources, they have to be marked as accessible in xCode's file inspector.
  • open or public functions and members can be accessed from anywhere within the target and from any other context that imports the current target’s module.

Interesting:

Instead of marking every single method or member as "private", you can cover some methods (e.g. typically helper functions) in an extension of a class / struct and mark the whole extension as "Private".

class foo { }

private extension foo {
    func somePrivateHelperFunction01() { }
    func somePrivateHelperFunction02() { }
    func somePrivateHelperFunction03() { }
}

This can be a good idea, in order to get better maintainable code. And you can easily switch (e.g. for unit testing) to non-private by just changing one word.

Apple documentation

Schopenhauerism answered 21/9, 2016 at 10:34 Comment(1)
Well, this answer was valid in the previous Swift version(s), it seems that it is not valid anymore :) please check my answer.Physiologist
S
1

One of the options you could use is to wrap the instance creation into a function and supply the appropriate getters and setters in a constructor:

class Counter {
    let inc: () -> Int
    let dec: () -> Int

    init(start: Int) {
        var n = start

        inc = { ++n }
        dec = { --n }
    }
}


let c = Counter(start: 10)

c.inc()  // 11
c.inc()  // 12
c.dec()  // 11
Sinclare answered 11/6, 2014 at 12:26 Comment(0)
P
0

The language grammar does not have the keywords 'public', 'private' or 'protected'. This would suggest everything is public. Of course, there could be some alternative method of specifying access modifiers without those keywords but I couldn't find it in the language reference.

Puttyroot answered 3/6, 2014 at 9:34 Comment(0)
A
0

Hopefully to save some time for those who want something akin to protected methods:

As per other answers, swift now provides the 'private' modifier - which is defined file-wise rather than class-wise such as those in Java or C# for instance. This means that if you want protected methods, you can do it with swift private methods if they are in the same file

  1. Create a base class to hold 'protected' methods (actually private)
  2. Subclass this class to use the same methods
  3. In other files you cannot access the base class methods, even when you subclass either

e.g. File 1:

class BaseClass {
    private func protectedMethod() {
        
    }
}

class SubClass : BaseClass {
    func publicMethod() {
        self.protectedMethod()  //this is ok as they are in same file
    }
}

File 2:

func test() {
    var a = BaseClass()
    a.protectedMethod() //ERROR


    var b = SubClass()
    b.protectedMethod() //ERROR
}

class SubClass2 : BaseClass {
    func publicMethod() {
        self.protectedMethod() //ERROR
    }
}
Abnaki answered 28/8, 2014 at 9:49 Comment(0)
P
-2

till swift 2.0 there were only three access level [Public, internal, private] but in swift 3.0 apple added two new access level which are [ Open, fileType ] so now in swift 3.0 there are 5 access level Here I want to clear the role of these two access level 1. Open: this is much similar to Public but the only difference is that the Public can access the subclass and override, and Open access level can not access that this image is taken from Medium website and this describe the difference between open and public access

Now to second new access level 2. filetype is bigger version of private or less access level than internal The fileType can access the extended part of the [class, struct, enum] and private can not access the extended part of code it can only access the lexical scope this image is taken from Medium website and this describe the difference between fileType and Private access level

Propinquity answered 25/7, 2017 at 1:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.