目录
属性是 Swift 编程中的基本组成部分,它们在类、结构体和枚举中存储和管理数据。属性可以分为存储属性、计算属性和属性观察者,每种属性都有其特定的用途和重要性。
在 Swift 编程中,属性是存储和管理数据的关键组件。属性可以分为存储属性和计算属性。在处理计算属性时,我们经常会使用到 getter 和 setter,这两个概念对于控制属性的读取和写入行为非常重要。
这篇博客主要介绍下Swift中的属性和settter和getter方法
Getter和Setter是访问属性值的两种方法。它们主要用于计算属性,通过这两种方法,我们可以在读取或设置属性值时执行特定的逻辑。
Getter 和 Setter 是访问属性值的两种方法。它们主要用于计算属性,通过这两种方法,我们可以在读取或设置属性值时执行特定的逻辑。
在Swift中,属性可以分为存储属性和计算属性。存储属性是类或者结构体的一部分,用来存储常来那个或者变量的值。它们是最基本的属性类型,直接存储在对象的内存中。
存储属性的类型
1.常量存储属性(let):定义后不能改变,只能初始化的时候设置值。
2.变量存储属性(var):定义后值可以改变。
我们可以通过下面的代码看一下存储属性的用法:
- struct Person {
- let firstName: String // 常量存储属性
- var lastName: String // 变量存储属性
- }
-
- var person = Person(firstName: "John", lastName: "Doe")
- print("Full Name: \(person.firstName) \(person.lastName)") // 输出: Full Name: John Doe
-
- // 修改 lastName 的值
- person.lastName = "Smith"
- print("Full Name: \(person.firstName) \(person.lastName)") // 输出: Full Name: John Smith
-
- // 尝试修改 firstName 的值(会产生编译错误)
- // person.firstName = "Jane"
在这个例子中,firstName
是一个常量存储属性,一旦赋值就不能改变。而 lastName
是一个变量存储属性,可以随时修改。
我们还可以使用lazy关键字来延迟存储属性。
- class DataManager {
- var data = [String]()
- init() {
- print("DataManager初始化.")
- }
- }
-
- class ViewController {
- lazy var dataManager = DataManager() // 延迟存储属性
- init() {
- print("ViewController初始化.")
- }
- }
-
- let viewController = ViewController()
- print("Accessing dataManager...")
- viewController.dataManager.data.append("Sample Data")
- print("DataManager data: \(viewController.dataManager.data)")
控制台输出结果如下:
我们可以看到,dataManager属性在首次访问的时候才被初始化,这样可以避免在ViewController初始化的时候进行不必要的开销。
可选类型的属性允许为空,可以使用?来定义可选类型的存储属性。
- struct Car {
- var model: String
- var owner: String?
- }
在下面的代码中,Car的owner属性就是可选的。
在 Swift 中,计算属性(Computed Properties)是类、结构体或枚举的一部分,它们不直接存储值,而是提供一个 getter 和可选的 setter 来间接获取和设置其他属性或值。计算属性在访问时动态计算其值。
我们可以使用var定义计算属性,提供一个getter和setter方法。getter用于计算和返回值,setter用来设置值。
以下面的代码为例,Rectangle的area属性是通过计算来获取的。
- struct Rectangle {
- var width: Double
- var height: Double
-
- var area: Double {
- return width * height
- }
- }
-
- let rect = Rectangle(width: 10.0, height: 5.0)
- print("Rectangle Area: \(rect.area)") // 输出: Rectangle Area: 50.0
上面的代码中,area属性是通过计算来获取的。例子中的area只读的,我们也可以设置既可读也可写的。
在下面的代码中,我们可以通过设置area获得height,也可以设置width和height获取area属性。
- struct Rectangle {
- var width: Double
- var height: Double
-
- var area: Double {
- get {
- return width * height
- }
- set {
- height = newValue / width
- }
- }
- }
-
- var rect = Rectangle(width: 10.0, height: 5.0)
- print("Rectangle Area: \(rect.area)") // 输出: Rectangle Area: 50.0
-
- rect.area = 100.0
- print("New Height: \(rect.height)") // 输出: New Height: 10.0
我们还可以给枚举类型设置计算属性,下面的例子中,我们定义了两个计算属性inCelsius和inFahrenheit,用于在摄氏度和华氏度之间转换温度。
- enum Temperature {
- case celsius(Double)
- case fahrenheit(Double)
-
- var inCelsius: Double {
- switch self {
- case .celsius(let value):
- return value
- case .fahrenheit(let value):
- return (value - 32) * 5 / 9
- }
- }
-
- var inFahrenheit: Double {
- switch self {
- case .celsius(let value):
- return (value * 9 / 5) + 32
- case .fahrenheit(let value):
- return value
- }
- }
- }
-
- let tempInCelsius = Temperature.celsius(25.0)
- print("Temperature in Fahrenheit: \(tempInCelsius.inFahrenheit)") // 输出: Temperature in Fahrenheit: 77.0
-
- let tempInFahrenheit = Temperature.fahrenheit(77.0)
- print("Temperature in Celsius: \(tempInFahrenheit.inCelsius)") // 输出: Temperature in Celsius: 25.0
在 Swift 中,属性观察者(Property Observers)可以监视和响应属性值的变化。无论新值是否与当前值相同,属性观察者都会在属性值改变时调用。你可以为存储属性添加观察者,但不能为计算属性添加观察者。
观察者属性有两种类型:
这两个观察者允许我们在属性值变化前后执行自定义的代码。willSet
会传入新的属性值作为参数,didSet
会传入旧的属性值作为参数:
例如下面的代码中,我们有一个StepCounter类,它有一个观察者属性couter,默认值为0
- class StepCounter {
- var counter: Int = 0 {
- willSet(counter) {
- print("counter willSet 设置为 \(counter)")
- }
- didSet {
- if counter > oldValue {
- print("counter didSet \(counter - oldValue) steps")
- }
- }
- }
- }
我们使用下面的代码调用它:
- let stepCounter = StepCounter()
- stepCounter.counter = 200
- stepCounter.counter = 360
- stepCounter.counter = 896
控制台打印信息如下:
属性观察者是 Swift 中强大的工具,用于监视和响应存储属性值的变化。通过 willSet
和 didSet
,你可以在属性值变化前后执行自定义操作。这对于验证数据、更新 UI 或者实现一些依赖逻辑非常有用。
上面介绍了属性的类型和getter和setter的用法,我们接下来看一下getter和setter的使用场景
- class Temperature {
- var celsius: Double = 0.0
-
- var fahrenheit: Double {
- get {
- return celsius * 9 / 5 + 32
- }
- set {
- celsius = (newValue - 32) * 5 / 9
- }
- }
- }
-
- var temp = Temperature()
- temp.celsius = 25
- print("Celsius: \(temp.celsius)") // Celsius: 25.0
- print("Fahrenheit: \(temp.fahrenheit)") // Fahrenheit: 77.0
-
- temp.fahrenheit = 98.6
- print("Celsius: \(temp.celsius)") // Celsius: 37.0
- print("Fahrenheit: \(temp.fahrenheit)") // Fahrenheit: 98.6
懒加载在iOS开发过程中经常使用,我们ViewController中使用的UI组件都可以使用懒加载的方式去声明。
- class DataManager {
- lazy var data: [String] = {
- // 复杂的初始化逻辑
- return ["Data1", "Data2", "Data3"]
- }()
- }
-
- let manager = DataManager()
- // Data will be loaded only when accessed for the first time
- print(manager.data) // ["Data1", "Data2", "Data3"]
例如在下面的代码中,我们可以使用set方法对输入的年龄做限制。
- class Person {
- private var _age: Int = 0
-
- var age: Int {
- get {
- return _age
- }
- set {
- if newValue >= 0 && newValue <= 120 {
- _age = newValue
- } else {
- print("Invalid age")
- }
- }
- }
- }
-
- var person = Person()
- person.age = 25
- print("Age: \(person.age)") // Age: 25
-
- person.age = -5 // Invalid age
- print("Age: \(person.age)") // Age: 25
例如在下面的Rectangle中,我们设置好width和height之后,会自动获取area的值。
- class Rectangle {
- var width: Double = 0.0
- var height: Double = 0.0
-
- var area: Double {
- get {
- return width * height
- }
- set {
- height = newValue / width
- }
- }
- }
-
- var rect = Rectangle()
- rect.width = 10
- rect.height = 5
- print("Area: \(rect.area)") // Area: 50.0
-
- rect.area = 100
- print("Height: \(rect.height)") // Height: 10.0
更多的时候,我们使用到setter和setter的场景是自定义我们自己的Getter和setter方法,格式如下:
- var propertyName: PropertyType {
- get {
- // 返回计算的值
- }
- set {
- // 执行自定义的设置逻辑
- }
- }
1. 官方文档链接