swift中跟实例相关的属性可以分为2大类
1、存储属性(Stored Property)
2、计算属性(Computed Property)
struct Circle {
//存储属性
var radius: Double
//计算属性
var diameter: Double {
set {
radius = newValue / 2
}
get {
radius * 2
}
}
}
存储属性(Stored Property)
- 类似于成员变量的概念
- 存储在实例的内存中
struct Point {
var x: Int
var y: Int
}
var p = Point(x: 10, y: 20)
print(MemoryLayout.stride(ofValue: p)) //16
//占用16个字节,其中8个用于x,8个用于y
- 结构体、类可以定义存储属性
- 枚举
不可以
定义存储属性
enum Season {
case spring, summer
}
var s = Season.spring
print(MemoryLayout.stride(ofValue: s)) // 1
//枚举变量只需要1个字节就可以知道区分知道存储的是哪一个case
//枚举可以设置关联类型
enum Season2 {
case spring(Int), summer(Double)
}
var s2 = Season2.spring(10)
print(MemoryLayout.stride(ofValue: s2)) // 16
//关联的Int类型也是存储在枚举变量内,占用8个字节
//原始值
enum Season3: Int {
case spring = 2, summer = 5
}
var s3 = Season3.spring
print(MemoryLayout.stride(ofValue: s3)) // 1
//枚举变量依然只需要1个字节就可以知道区分知道存储的是哪一个case
//所以枚举类型内存中要么存储case用来区分,要么用来存储关联类型,
关于存储属性,Swift有个明确的规定
在创建类或者结构体实例的时候,必须为所有的存储属性设置一个合适的初始值
- 可以在初始化器里面为存储属性设置一个初始值
struct Point {
var x: Int
var y: Int
init() {
x = 10
y = 10
}
}
- 可以分配一个默认的属性值作为属性定义的一部分
struct Point {
var x: Int = 11
var y: Int = 12
}
计算属性(Computed Property)
- 本质就是方法(函数)
- 不占用实例的内存
- 枚举、结构体、类都可以定义计算属性
struct Circle {
//存储属性
var radius: Double
//计算属性
var diameter: Double {
set {
radius = newValue / 2
}
get {
radius * 2
}
}
}
var c = Circle(radius: 10)
print(MemoryLayout.stride(ofValue: c)) // 8
一个结构体变量c
占用8
个字节,一个Double
也占用8
个字节,所以说明了计算属性diameter
不占用结构体变量c
的内存,它本质是一个方法实现,不存在diameter
这个成员变量。
var c = Circle(radius: 10)
print(c.radius) // 10.0
print(c.diameter) // 调用diameter的get方法,计算 radius * 2 = 20.0
c.radius = 15
print(c.diameter) // 调用diameter的get方法,计算 radius * 2 = 30.0
c.diameter = 60 // 调用diameter的set方法,会导致radius重新计算 radius = newValue / 2
print(c.radius) // 30.0
一些注意点
1、set
传入的新值默认叫做newValue
,也可以自定义
struct Circle {
var radius: Double
var diameter: Double {
set(newDiameter) {
radius = newDiameter / 2
}
get {
radius * 2
}
}
}
2、只读计算属性:只有get
,没有set
struct Point {
var x: Int
var y: Int {
get {
10
}
}
}
var p = Point(x: 10)
p.y = 20 //报错:Cannot assign to property: 'y' is a get-only property
//只有get,可以省略写法
struct Point {
var x: Int
var y: Int { 10 }
}
3、计算属性只能用var
,不能用let
,即使它是只读计算属性
struct Point {
var x: Int
let y: Int { 10 } //报错:'let' declarations cannot be computed properties
}
4、枚举rawValue
原始值的本质就是一个只读的计算属性
enum Season: Int {
case spring = 1, summer, autum, winter
var rawValue: Int {
switch self {
case .spring:
return 11
case .summer:
return 12
case .autum:
return 13
case .winter:
return 14
}
}
}
var s = Season.spring
print(s.rawValue) // 1
s.rawValue = 20 //报错:Cannot assign to property: 'rawValue' is a get-only property
5、通过private(set)
设置属性为readonly
,在当前文件内可以修改,外部引用只能读取
private(set) var name: String
延迟存储属性(Stored Property)
使用lazy
可以定义一个延迟存储属性,在第一次用到属性的时候才会进行初始化,类似懒加载
1、延迟存储属性必须用var
2、当结构体包含一个延迟存储属性时候,只有var
才能访问延迟存储属性,因为延迟属性初始化时候需要改变结构体的内存
属性观察器(Property Observer)
1、可以为非lazy
的var
存储属性设置属性观察器(类似KVO)
-
willSet
会传递新值,默认叫newValue
-
didSet
会传递旧值,默认叫oldValue
- 在初始化器中设置属性值不会触发
willSet
和didSet
struct Circle {
var radius: Double {
willSet {
print("willSet", newValue)
}
didSet {
print("didSet", oldValue, radius)
}
}
init() {
self.radius = 1.0
print("Circle init")
}
}
//Circle init
var circle = Circle()
//willSet 10.5
//didSet 1.0 10.5
circle.radius = 10.5
//10.5
print(circle.radius)
全局变量、局部变量
属性观察器、计算属性的功能,同样可以应用在全局变量、局部变量上
var num: Int {
get {
return 10
}
set {
print("setNum", newValue)
}
}
num = 11 // setNum 11
print(num) // 10
func test() {
var age: Int = 10 {
willSet {
print("willSet", newValue)
}
didSet {
print("didSet", oldValue, age)
}
}
age = 11
// willSet 11
// didSet 10 11
}
test()
类型属性(Type Property)
严格来讲,属性可以分为:
1、实例属性(Instance Property):只能通过实例去访问
* 存储实例属性(Stored Instance Property):存储在实例的内存中,每个实例都有1份
* 计算实例属性(Computed Instance Property)
2、类型属性(Type Property):只能通过类型去访问
* 存储类型属性(Stored Type Property):整个程序运行中,就只有1份内存(类似于全局变量)
网友评论