Access Control in Swift
Sep 07, 2022This guide will explain how to make your code more or less accessible by using Swift's access controls.
Basically, access controls in swift are used to define how types, functions, and other declarations can be accessed in your project. You can set the accessibility (visibility) of classes, structs, enums, functions, variables, and so on.
Swift provides a variety of access controls that can be used for different purposes. These are:
- Open
- Public
- Internal
- Fileprivate
- Private
Different Access Controls
Open Access (less restrictive)
It 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. Use open or public access when specifying the public interface to a framework.
Public Access (more restrictive than open)
It 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.
For example, you have created a separate module named Utility for an image downloading class, initially, the class looked like this:
class ImageDownloader { ... }
As you can see there is no access specifier here, when we will try to access this class from our main app or another module the compiler will raise an error saying "unable to access internal class ImageDownloader".
To make the class accessible to other module you will have to add public access modifier to it like:
public class ImageDownloader { ... }
Internal Access (module-level access control)
It enables entities to be used within any source file from their defining module, but not in any source file outside of that module. By default if you don't specify any access modifier, every entity is treated as internal.
File-private Access (file-level access control)
It 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.
Let's see an example:
import Foundation
class Student {
var name = ""
fileprivate var rollNumber = 0
}
class College {
var students: [Student] = []
func displayRollNumbers() {
students.forEach { student in
print(student.rollNumber)
}
}
}
In the above example, we have created two class i.e. Student
and College
into a single source file.
You can see, the variable rollNumber
is accessible in College
class as it is marked as file-private.
Then how we are hiding entities using file-private?
import UIKit
class CollegeViewController: UIViewController {
var students: [Student] = []
override func viewDidLoad() {
super.viewDidLoad()
students.forEach { student in
print(student.rollNumber)
// 'rollNumber' is inaccessible due to 'fileprivate' protection level
}
}
}
In the above code, we have created another file called CollegeViewController
and now trying to access student's roll number. Now you can see it is not accessible in this class as it is file-private.
Private Access (class-level access control)
It 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.
Let's see an example:
class Student {
var name = ""
private var rollNumber = 0
func uniqueId() {
print(rollNumber)
}
}
In above example, you can see there is a variable called rollNumber
which is private. Mean, you cannot access it outside the class scope.
let alex = Student()
print(alex.rollNumber) // Cannot access it as it is private.
print(alex.name) // Accessible outside the class scope.
So basically, which entities you don't want to access outside the class, mark them as private to make them safe.
What’s the difference between open and public?
Entities defined as public or open are accessible by modules that import the defining module to access it. But the difference between the two is overridability. Entities defined as open are overridable but the ones defined as public are available for other modules but cannot be overridden.
For example, when importing UIKit, here are some functions related to UICollectionView:
// This open function is overridden to return the number of sections in the collection view and is also available to get the number of sections.
open func numberOfSections(in collectionView: UICollectionView) -> Int
// This public function is available for us to use but we cannot override the response.
public func description() -> String
What’s the difference between private and file-private?
File-private and private sound similar but the difference can be understood from the name as well. File-private entities are available within the same file but not accessible outside the source file. Private entities are available only inside the type where it’s declared or the extensions of the type.
For example -
class Anytime {
private func taylor() { }
fileprivate func swift() { }
}
let anytime = Anytime()
a.taylor() // error: 'taylor' is inaccessible due to 'private' protection level
a.swift()
Conclusion
Now that you understand open access is the highest (least restrictive) access level to private access which is the lowest (most restrictive) access level, use them wisely.
What next?
In this article, you learned about access controls, and how they are works on different levels. We encourage you to read more related articles like, Variables in Swift, Functions in Swift.