Swift Access Control
Access control lets you restrict which parts of your code can see and use a given declaration, hiding implementation details behind clear boundaries.
The Five Access Levels
Swift provides five access levels, from most to least restrictive: private, fileprivate, internal, public, and open. Every declaration defaults to internal unless you specify otherwise, which is why most code you write never mentions access control at all.
Private and File-Private
private restricts a declaration to its enclosing scope (and extensions of that type in the same file). fileprivate widens that to the whole file, which is useful when two closely related types in one file need to share internals that outside code shouldn't touch.
Private Properties
class BankAccount {
private var balance: Double = 0
fileprivate var accountNumber: String
init(accountNumber: String) {
self.accountNumber = accountNumber
}
func deposit(_ amount: Double) {
balance += amount
}
func currentBalance() -> Double {
return balance
}
}
let account = BankAccount(accountNumber: "AC-1001")
account.deposit(250.0)
print(account.currentBalance()) // 250.0
// account.balance would fail to compile — balance is privateInternal — the Default
If you write no access modifier at all, a declaration is internal: visible anywhere inside the same module (your app target or framework), but invisible to any other module that imports it. Most application code stays at this level.
Internal by Default
struct Product {
var name: String // internal by default
var price: Double // internal by default
func formattedPrice() -> String {
return String(format: "$%.2f", price)
}
}
let item = Product(name: "Keyboard", price: 49.99)
print(item.formattedPrice()) // $49.99
// Visible anywhere inside this module, but not to code
// that imports this module from outside.Public and Open
public exposes a declaration to other modules but prevents them from subclassing a class or overriding its members. open goes one step further, explicitly allowing external subclassing and overriding — the right choice when you're designing a framework's extension points.
Public API With an Override Point
open class Shape {
public var name: String
public init(name: String) {
self.name = name
}
open func area() -> Double {
return 0.0
}
}
public class Circle: Shape {
public var radius: Double
public init(radius: Double) {
self.radius = radius
super.init(name: "Circle")
}
public override func area() -> Double {
return Double.pi * radius * radius
}
}
let circle = Circle(radius: 3.0)
print(circle.area()) // 28.274333882308138- Start with private and widen access only when something outside genuinely needs it
- Use internal (the default) for anything the rest of your app needs but external packages don't
- Reserve public and open for real library APIs meant for consumption outside your module
- Use open only when external modules should be able to subclass or override
Exercise: Swift Access Control
What does the private access level restrict?