The access control in Swift is much more like the access control I am accustomed to in other languages like C# or Java, and I am quite thankful for that. I’m not saying there is anything wrong with Objective-C’s way of doing it, while it was different, I did like having the private properties in the interface block of the implementation (.m) file, and the public properties and methods in the header (.h) file. It made it easy to know exactly where to look.
Nonetheless, access control is here in Swift, so here we go. You can set access control to many things in Swift, particularly properties and methods, but you can even set it to types, initializers, subscripts, or protocols. Swift currently has three levels of access control:
- Public
- Internal
- Fileprivate
- Private
The section in Apple’s iBook The Swift Programming Language, described the major differences between them in a few paragraphs, when writing this, I kept having to look back to remember the specific aspects of where they were all visible. So, I thought it would be better to show the major differences in tabular form…. behold:
Visible to… | Defining Scope | Defining Source | Defining Module |
Source that Imports Defining Module |
Public | ✓ | ✓ | ✓ | ✓ |
Internal | ✓ | ✓ | ✓ | |
Fileprivate | ✓ | ✓ | ||
Private | ✓ |
Now, we haven’t talked about Module’s yet on this blog, but basically, this is Swift’s name for “namespaces” in other languages. They are also part of how Apple makes headers unnecessary in Swift. Effectively, a module is basically the target you are building for. For most of us, that means “your app,” but it could also be a framework instead.
Let’s look a little more in depth into these access control levels.
Swift Access Controls
Public
As expected, public is the most visible access control level you can have. It allows the user to use that property, function, etc in the defining source, the module that source is in, and anything that imports that module. Basically, it can be seen anywhere. This is particularly important for frameworks. This is what will give your framework a public API, to be called by whatever imports your framework.
Internal
This is the default access level. It can be seen in the defining source, as well as the module that source is in, but it cannot be seen by something that imports that module. If used in a framework, it lets other parts of your module see these aspects, but not something that imports your module. In Objective-C, it would basically be equivalent to having them declared in your header file.
Fileprivate
Fileprivate can only be seen in the defining source. This hides the implementation details of that source file, so that the rest of your module does not have access to parts that have little meaning outside of the context of the original source file. In Objective-C, it would be equivalent to being declared in the interface part of your implementation file.
Private
This is the least visible access control level. Private can only be seen in the defining scope. So if you made an extension of your class in the same source file, but wanted a function only visible in that extension and not in the main class, you would declare it private.
The @testable Attribute
Since the release of Swift 2, these issues have been mitigated with the addition of the ” @testable ” import attribute. It basically treats anything that is marked as “internal” as if it were public, to the code that imports using that attribute. So to test with your internal methods, properties, types, etc., in your unit test class, just “@testable” before the import of whichever module you are testing.
Using Access Controls
With all this talk about access controls, I should probably show how they are used? Well, they are really simple, you basically just begin your declaration of a variable or class with the access modifier you want, so:
public class myPublicTranslator { } public func translateSomeText(inputText: String) -> String { } fileprivate let implementationDetail = "A Secret" private let superSecretImplementationDetail = "A SUPER Secret"
Nothing too special there.
Limitations to Access Controls
There are a few limitations to access controls, and most of them are just to enforce common sense. For instance, a public variable cannot have an internal or private type. That seems pretty obvious. If the type was private, how could anything that can only read the public variable have access to it?
Another similarly obvious one, a function can have an access level no more visible than the least visible type in its parameters or return value. You can make a private type that contains public and internal types as parameter or return types. However, you cannot make a public function that uses internal parameter or return types. Similar reasoning, since nothing from another module that can only read public items could possibly have access to internal or private types.
Conclusion
Access controls are definitely a welcome addition to Swift. They will make it much easier to enforce interfaces between your source files and modules, as opposed to just leaving your implementation details out for all to see.
I hope you found this article helpful. If you did, please don’t hesitate to share this post on Twitter or your social media of choice, every share helps. Of course, if you have any questions, don’t hesitate to contact me on the Contact Page, or on Twitter @CodingExplorer, and I’ll see what I can do. Thanks!