Encapsulation
Essence
Encapsulation means bundling data together with the behaviour that works on it inside one type and controlling access to that state. The outside sees only the contract (the public interface), while invariants ("balance is never negative") are protected inside the type. This localizes change: you can rewrite how data is stored without touching clients.
What it looks like in Swift
Access levels from most restrictive to most open: private (inside the declaration and its extensions in the same file), fileprivate, internal (the default, whole module), package (several modules of one package, Swift 5.9), public (visible from other modules), open (can also be subclassed/overridden outside the module). private(set) lets everyone read but only the type itself write.
import Foundation
struct BankAccount {
private(set) var balance: Decimal = 0
private var history: [Decimal] = []
mutating func deposit(_ amount: Decimal) {
precondition(amount > 0)
balance += amount
history.append(amount)
}
}
var account = BankAccount()
account.deposit(100)
print(account.balance) // 100
// account.balance = 1_000 // error: setter is private
What the interviewer looks for
- Encapsulation is not "hide everything" but expose the minimal contract and guard invariants. Properties with
didSetor computed properties let you change the implementation without changing the API. privatein Swift is file-scoped forextensions, not class-scoped as in Java: a common trick question.- Value types strengthen encapsulation: a copy of a
structshares no state with the original, so foreign code cannot mutate your object through a stray reference. @testable importexposesinternalto tests but notprivate: test behaviour through the public API.