Swift中的private(set) 是一种访问控制的声明,表示属性可以被外部读取,但只能在定义它的作用域内修改。这是一种保护机制,常用于保证数据的完整性和安全性。
@Observable
class ViewModel {
private(set) var locations = [Location]()
var selectedPlace: Location?
}
private(set) 的作用
限制写权限:locations 的值只能在定义它的作用域(通常是当前类或结构体)内被修改。
允许读权限:外部仍然可以通过 viewModel.locations 访问和读取它的值,但无法直接修改。
class ViewModel {
private(set) var locations = [Location]()
func addLocation(_ location: Location) {
locations.append(location) // 内部可以修改
}
}
let viewModel = ViewModel()
print(viewModel.locations) // 外部可以读取
// viewModel.locations.append(Location(...)) // 外部不能直接修改
为什么使用 private(set)?
1、保护数据完整性
让外部代码无法随意更改数据,避免意外或恶意的修改。
只允许通过类或结构体中定义的方法来修改数据,这样可以确保修改时符合业务逻辑。
例子:
class BankAccount {
private(set) var balance = 0
func deposit(amount: Int) {
guard amount > 0 else { return }
balance += amount
}
}
let account = BankAccount()
account.deposit(amount: 100)
print(account.balance) // 100
// account.balance = 200 // 不允许直接赋值
2、清晰的接口设计
外部代码只能读取 locations,修改逻辑由 ViewModel 自己管理。这使得接口更加清晰,减少了误用的可能性。
3、便于调试和维护
当数据只能通过受控的方法修改时,更容易在代码中跟踪数据的变化来源。
private(set) vs 完全 private
1、private:
属性既不能被外部读取,也不能被外部修改。
使用场景:完全隐藏内部实现细节。
2、private(set):
属性可以被外部读取,但不能被外部修改。
使用场景:需要外部访问数据,但不希望外部修改数据。
总结
private(set) 是一种限定写权限的修饰符,用于在保持外部可访问性的同时保护数据不被随意修改。这种模式在 Swift 的 MVVM 架构中非常常见,因为它允许 View 层读取数据,但确保所有的数据更新只能通过 ViewModel 的方法进行,从而维护了逻辑的集中性和一致性。