Access control specifies which methods and properties can be accessed from outside that scope of a structure, file, or module. Access control makes it possible to hide implementation details and protect properties from being changed at unexpected times.
Swift provides several different levels of access. From least restrictive to most restrictive they are:
// public structures can be accessed in other modulespublic struct User {// internal is the default level of access controllet name: String// fileprivate methods can only be accessed inside of the file they're declared infileprivate func incrementVisitCount() {visitCount += 1}// private properties can only be accessed inside their structure's definitionprivate let visitCount = 0}
Mark methods and properties as private
to prevent them from being accessed outside of the structure, class, or enumeration’s definition.
struct User {let name: Stringinit(name: String) {self.name = nameuploadNewUser()}private func uploadNewUser() {print("Uploading the new user...")}}
Read-only computed properties can be accessed, but not assigned to a new value. To define a read-only computed property, either use the get
keyword without a set
keyword, or omit keywords entirely.
struct Room {let width: Doublelet height: Doublevar squareFeet: Double {return width * height}var description: String {get {return "This room is \(width) x \(height)"}}}
Property observers execute code whenever a property is changed. The willSet
property observer is triggered right before the property is changed and creates a newValue
variable within the block’s scope. The didSet
property observer is triggered right after the property is changed and creates an oldValue
within the block’s scope.
struct Employee {var hourlyWage = 15 {willSet {print("The hourly wage is about to be changed from \(hourlyWage) to \(newValue)")}didSet {print("The hourly wage has been changed from \(oldValue) to \(hourlyWage)")}}}var codey = Employee()codey.hourlyWage = 20// Prints:// The hourly wage is about to be changed from 15 to 20// The hourly wage has been changed from 15 to 20
Properties marked as private(set)
can be accessed from outside the scope of its structure, but only assigned within it. This allows the setter to be more restrictive than the getter.
struct User {private(set) var name: Stringmutating func updateName(to newName: String) {if newName != "" {name = newName}}}var currentUser = User(name: "codey")currentUser.updateName(to: "Codey")print(currentUser.name)// currentUser.name = "Bob" // This line doesn't compile because the 'name' setter is inaccessible
The static
keyword is used to declare type methods and properties. These are accessed from the type itself rather than an instance.
struct User {static var allUsers = [User]()let id: Intinit(id: Int) {self.id = idUser.allUsers.append(self)}}let userOne = User(id: 1)let userTwo = User(id: 2)let userThree = User(id: 3)print(User.allUsers) // Prints: [User(id: 1), User(id: 2), User(id: 3)]
The extension
keyword is used to continue defining an existing class, structure, or enumeration from anywhere in a codebase. Extensions can have new methods, internal types, and computed properties, but can’t contain new stored properties.
struct User {let name: String}extension User {var description: String {return "This is a user named \(name)"}}