Access controls
Access control in Swift defines the scope and visibility of classes, structs, enums, functions, variables, and other identifiers within a codebase. By specifying the access level, you can restrict the parts of the code that can read or modify the elements. This is essential for encapsulation and can protect the integrity of the data structure by only exposing a well-defined interface.
Swift provides five different access levels:
Open / Public: These identifiers can be accessed from any source file in their defining module or in another module that imports their defining module. open is more permissive than public, allowing a class to be subclassed and a method to be overridden in a different module.
open class OpenClass {}
public class PublicClass {}
Internal: This is the default access level. Identifiers with internal access can be accessed within the same module but not in other modules.
internal class InternalClass {} // The 'internal' keyword is often omitted because it's the default.
File-private: Identifiers with fileprivate access can be accessed only within the same source file.
fileprivate class FilePrivateClass {}
Private: These identifiers can only be accessed within the immediate lexical scope in which they are declared. This is the most restrictive access level.
private class PrivateClass {}
Access Control Syntax
You can specify the access level by placing one of the access control keywords before the element you want to restrict:
public class PublicClass {
public var publicProperty: Int = 0
internal var internalProperty: Int = 0 // This is the default, so 'internal' can be omitted.
fileprivate var filePrivateProperty: Int = 0
private var privateProperty: Int = 0
}
Subclassing and Overriding
When subclassing, the subclass cannot have a higher (i.e., more permissive) access level than the superclass. Also, you can override a method, property, or subscript in a subclass as long as the overriding element is at least as accessible as the element it overrides.
Getters and Setters
Swift allows you to specify access levels for getters and setters independently. This is especially useful for read-only computed properties.
public struct TrackedString {
public private(set) var numberOfEdits = 0 // 'numberOfEdits' is publicly readable but only privately settable.
}
Extensions
If you mark an extension with an access level, that access level will apply as the default for all members within the extension:
private extension String {
var secretData: String {
return "This is secret."
}
}
Protocols
If you want to restrict the adoption of a protocol or the visibility of its methods, you can apply access control to the protocol similar to classes and structs.
public protocol PublicProtocol {
func publicMethod()
}
In summary, access control is an essential tool for encapsulating and protecting code, offering various levels of visibility from open APIs to tightly-scoped, private implementations.