在Swift中,`set`和`get`方法用于定义属性的读取和设置行为。Swift中的属性可以是存储型属性(stored properties)或计算型属性(computed properties)。计算型属性没有实际的存储空间,它们的值是动态计算出来的。
一、下面是一些Swift中使用`set`和`get`方法的例子:
### 存储型属性
对于存储型属性,`get`方法默认是存在的,用于读取属性值。`set`方法可以在属性值被设置时执行额外的操作。
```swift
class Person {
var name: Stringinit(name: String) {
self.name = name
}// 存储型属性,添加自定义的setter和getter
var age: Int {
get {
return _age
}
set {
if newValue > 0 {
_age = newValue
} else {
print("年龄必须大于0")
}
}
}
private var _age: Int = 0 // 私有的存储变量
}let person = Person(name: "Alice")
print(person.age) // 使用getter获取age的值
person.age = 30 // 使用setter设置age的值
person.age = -1 // 尝试设置一个无效的年龄,将会打印错误信息
```
### 计算型属性
计算型属性没有存储空间,它们的值是每次访问时计算得出的。
```swift
struct Circle {
var radius: Double// 计算型属性,使用getter来返回面积
var area: Double {
get {
return Double.pi * radius * radius
}
}// 计算型属性可以没有setter,如果需要setter也可以定义
var diameter: Double {
get {
return 2 * radius
}
set {
radius = newValue / 2
}
}
}let circle = Circle(radius: 10)
print(circle.area) // 使用getter获取面积
circle.diameter = 20 // 使用setter设置直径,这将更新radius
```
二、### 观察者(willSet 和 didSet)
Swift还提供了`willSet`和`didSet`属性观察者,它们允许你在属性值被设置之前或之后执行代码。
```swift
class Account {
var balance: Double = 0.0 {
willSet(newBalance) {
print("即将设置新余额: \(newBalance)")
}
didSet {
if balance < 0 {
print("余额不足")
}
}
}
}let account = Account()
account.balance = 100 // 将打印 "即将设置新余额: 100"
account.balance = -50 // 将打印 "即将设置新余额: -50" 然后是 "余额不足"
```
在这些例子中,`get`方法用于获取属性的值,`set`方法用于设置属性的值,并且可以在设置值时执行额外的逻辑。计算型属性的`get`方法定义了如何计算属性的值,而`willSet`和`didSet`观察者提供了在属性值变化前后执行代码的能力。
在Swift中,当你为类或结构体中的属性设置初始值时,并不会触发`willSet`或`didSet`观察者。这是因为初始值是在实例化过程中设置的,此时属性的观察者逻辑尚未开始执行。
在你提供的`Account`类示例中:
```swift
class Account {
var balance: Double = 0.0 {
willSet(newBalance) {
print("即将设置新余额: \(newBalance)")
}
didSet {
if balance < 0 {
print("余额不足")
}
}
}
}
```
当创建`Account`类的实例时,`balance`属性被初始化为`0.0`,这个值是直接赋值的,不会触发`willSet`或`didSet`观察者。这意味着,当你创建一个`Account`实例时,下面的代码:
```swift
let account = Account()
```
不会打印出任何关于`willSet`或`didSet`的消息。只有当`balance`属性的值在初始化之后被显式修改时,才会触发这些观察者:
```swift
account.balance = 100.0 // 这将触发 willSet 和 didSet
```
在这个例子中,将`balance`设置为`100.0`会触发`willSet`观察者,打印出"即将设置新余额: 100.0",然后设置新值,接着触发`didSet`观察者,但由于新余额是正数,不会打印"余额不足"的消息。如果将`balance`设置为一个负数,比如:
```swift
account.balance = -50.0 // 这将触发 willSet 和 didSet,并打印 "余额不足"
```
此时,`willSet`会先打印出"即将设置新余额: -50.0",然后设置新值,`didSet`会检测到余额不足,并打印出相应的消息。
三、那如果在 didSet观察者 中判断值真正改变时再触发逻辑,该如何实现?
在Swift中,`didSet`观察者默认会在每次属性值被设置时触发,无论新的值是否与旧值不同。如果你只想在属性值真正改变时执行某些逻辑,你可以在`didSet`中添加一个条件判断,来检查新旧值是否不同。
这里是如何实现这一点的示例:
```swift
class Account {
var balance: Double = 0.0 {
willSet(newBalance) {
print("即将设置新余额: \(newBalance)")
}
didSet {
// 只有当余额真正改变时才执行逻辑
if balance != oldValue {
print("余额已从 \(oldValue) 改变到 \(balance)")
if balance < 0 {
print("余额不足")
}
}
}
}
}
```
在这个例子中,`didSet`观察者使用了`oldValue`这个隐含参数,它代表属性在这次赋值之前的值。通过比较`balance`(新值)和`oldValue`(旧值),你可以判断属性值是否真正发生了变化。如果它们不相等,那么你可以执行你的逻辑代码。
使用这种方式,你可以避免在属性值未改变的情况下执行不必要的操作。例如:
```swift
let account = Account() // 初始赋值,不触发 didSet
account.balance = 100.0 // 余额改变,触发 didSet
account.balance = 100.0 // 余额未变,didSet 不会打印余额改变的消息
account.balance = -50.0 // 余额改变,触发 didSet 并检查余额是否不足
```
在这个例子中,只有当`balance`的值从初始值`0.0`变为`100.0`和从`100.0`变为`-50.0`时,`didSet`观察者中的逻辑才会执行。当尝试将`balance`重新设置为`100.0`时,由于新旧值相同,`didSet`不会执行任何操作。