# 属性

Swift中的属性分为`存储属性`和`计算属性`。

存储属性会将常量和变量存储为实例的一部分。

计算属性则是返回一个计算后的值，而非存储的值。

计算属性可以用于类，结构体和枚举；存储属性只能用于类和结构体。

## 1. 存储属性

`存储属性`定义在`class`和`struct`之中，是对象的数据成员的一部分，需要占据内存空间。

`class`和`struct`必须要提供`初始化所有存储属性`的构造器。`struct`会自动生成一个构造器；`class`则必须手动实现。

![](https://pic.existorlive.cn/%E6%88%AA%E5%B1%8F2020-11-30%20%E4%B8%8A%E5%8D%8812.51.40.png)

```swift

struct FixedLengthRangeStruct {
    var firstValue: Int           // 变量
    let length: Int               // 常量
}

// struct 会自动生成为每个存储属性初始化的构造器
let obj1 : FixedLengthRangeStruct = FixedLengthRangeStruct(firstValue:12,length:12)

class FixedLengthRangeClass {
    var firstValue: Int           // 变量
    let length: Int               // 常量   

    init(){
        firstValue = 13
        length = 13
    }
}

let obj2 = FixedLengthRangeClass()  


```

### 1.1 定义存储属性时提供初始值

当为常量属性提供初始值时，构造器中不可以再重新赋值。

当为变量属性提供初始值时，构造器中仍可以再重新赋值

```swift

struct FixedLengthRangeStruct {
    var firstValue: Int 
    let length: Int = 13
    var strArray : [String] = []
}

// struct 会自动生成为每个存储属性初始化的构造器
let obj1 : FixedLengthRangeStruct = FixedLengthRangeStruct(firstValue:12)

class FixedLengthRangeClass {
    var firstValue: Int           // 变量
    let length: Int               // 常量   
    var strArray : [String] = []

    init(){
        firstValue = 13
        length = 13
        // 定义时提供初始值的属性不需要在构造器中再提供初始值
    }
}

let obj2 = FixedLengthRangeClass()  


```

### 1.2 延时加载存储属性

`延时加载存储属性`是指当第一次被访问的时候才会计算其初始值的属性。

```swift
struct FixedLengthRangeStruct {
    lazy var firstValue: Int = Int(15)
    let length: Int = 13
}
```

> 延时加载属性必须声明为变量

> 延时加载属性必须提供初始化器

> 延迟加载属性不能保证线程安全

`延时加载存储属性`在对象初始化之后,才会初始化。因此不可以声明为常量。同时必须在声明时提供一个初始化器。

`延时加载存储属性`适用于一些需要较大开销才能够获得属性。因此将属性的初始化时机推迟到使用时。

### 1.3 常量结构体实例的存储属性

类或者结构体实例中的常量成员在初始化之后不可以再修改。

> 常量的结构体实例中的属性,无论是常量还是变量都不可以修改

> 常量的类实例中的变量属性可以修改

![](https://pic.existorlive.cn/%E6%88%AA%E5%B1%8F2020-11-30%20%E4%B8%8A%E5%8D%882.02.55.png)

```swift

// 结构体
struct FixedLengthRange {
    var firstValue: Int
    let length: Int
}

let obj1 : FixedLengthRange = FixedLengthRange(firstValue:12,length:13)
obj1.firstValue = 15    // 报错

// 类
class FixedLengthRange {
    var firstValue: Int
    let length: Int
    init(){
        firstValue = 15
        length = 13
    }
}

let obj2 : FixedLengthRange = FixedLengthRange()
obj2.firstValue = 15    // 可以重新赋值

```

## 2. 计算属性

`计算属性`不同于`存储属性`，不需要存储值，不会在对象实例中占据内存。通过提供setter，getter方法，来间接获取和设置其他属性或变量的值。

`类`，`结构体`以及`枚举`都可以定义`计算属性`。

计算属性必须使用`var`声明

```swift
struct Point {
    var x = 0.0, y = 0.0
}
struct Size {
    var width = 0.0, height = 0.0
}
struct Rect {
    var origin = Point()
    var size = Size()
    var center: Point {
        get {
            let centerX = origin.x + (size.width / 2)
            let centerY = origin.y + (size.height / 2)
            return Point(x: centerX, y: centerY)
        }
        set(newCenter) {
            origin.x = newCenter.x - (size.width / 2)
            origin.y = newCenter.y - (size.height / 2)
        }
    }
}
```

### 2.1 简化Setter和Getter声明

```swift
struct Rect {
    var origin = Point()
    var size = Size()
    var center: Point {
        get {
            // 单行表达式可以参略return 
            Point(x: origin.x + (size.width / 2), y: origin.y + (size.height / 2))
        }
        set{
            // setter可以不用提供新值的参数名，可以使用默认名称newValue
            origin.x = newValue.x - (size.width / 2)
            origin.y = newValue.y - (size.height / 2)
        }
    }
}

```

### 2.2 只读计算属性

只有 `getter` 没有 `setter` 的计算属性叫只读计算属性。

```swift

struct Cuboid {
    var width = 0.0, height = 0.0, depth = 0.0
    // 只读计算属性可以省略get{}
    var volume: Double {
        return width * height * depth
    }
}
```

## 3. 存储属性和计算属性

* 存储属性
  * 存储属性需要存储值，占据对象的内存
  * 存储属性可以定义为常量和变量
  * 只有类和结构体才能够定义存储属性
  * 存储属性需要提供初始化器或者在构造器中初始化
  *
* 计算属性
  * 计算属性不需要存储值，但是需要提供setter和getter方法
  * 计算属性只能使用`var`声明
  * 类，结构体和枚举都可以定义计算属性
  *


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gitbook.existorlive.cn/kai-fa-yu-yan-xue-xi/swift/9.-lei-he-jie-gou-ti/shu-xing/2.1-shu-xing.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
