属性将值跟特定的类、结构或枚举关联。存储属性存储常量或变量作为实例的一部分,而计算属性计算(不是存储)一个值。计算属性可以用于类、结构体和枚举,存储属性只能用于类和结构体,总结swift中属性的分类,主要可以分为以下几个:
-
存储实例属性(Stored Instance Property):存储在实例的内存中的属性,只有一份
-
计算实例属性(Computed Instance Property):不占用系统内存,调用的时候才计算得出的实例属性,类似实例的方法
-
存储类属性(Stored Type Property):整个程序运行过程中就只有一份内存,类似全局变量或常量
-
计算类属性(Computed Type Property):不占用系统内存,调用的时候才计算得出的属性,类似全局函数
一、存储属性
存储属性是一个作为特定类和结构体实例一部分的常量或变量。存储属性要么是变量存储属性(由 var 关键字引入)要么是常量存储属性(由 let 关键字引入)。
1、存储实例属性
var name = "姓名"//变量
let age = 22//常量
- 创建类或者结构体时,所有存储实例属性必须初始化(设置初始值或者在
init中赋值) extension中不能定义存储实例属性
2、存储类属性(类、结构体、枚举中使用static定义)
static var name = "姓名"
static let age = 20
- 存储类属性必须有初始值,不用使用
init初始化 - 存储类属性只会在第一次使用的时候初始化
- 存储类属性不能在子类中被重写
extension中可以定义储存类型属性,我们可以用这种方法,扩展UIKit里常用的类,比如UIColor、UIFont等
二、计算属性
类、结构体和枚举也能够定义计算属性,计算属性并不存储值,他们提供 getter 和 setter 来修改和获取值。对于存储属性来说可以是常量或变量,但计算属性必须定义为变量。于此同时我们书写计算属性时候必须包含类型,因为编译器需要知道期望返回值是什么。
1、计算实例属性
var x = 20
var y = 10
var z:Int {
get {
return x + y
}
}
print(z)//z = 30
-
计算属性不存储值,不用初始化,但至少需要提供一个getter(
get)取值,setter(set)赋值是可选的 -
定义计算属性只能使用
var, 不能使用let -
如果
get中只有一条return语句,则可以省掉return和get关键字 -
entension可以定义计算属性 -
可以在协议(
protocol)的extension中定义计算实例属性,这样相当于实现了协议中的一个成员 -
枚举的
rawValue的本质就是实例计算属性, 而且是只读的计算属性 -
我们可以在
enum重新定义rawValue计算属性
2、计算类属性(同存储实例属性一样,定义计算类属性也是要加上static关键字,不同的是类中还可以用class关键字定义)
static var a:String {
return "好"
}
class var b:String {
return "是"
}
-
同计算实例属性一样,定义计算属性只能使用
var, 不能使用let -
使用
class关键字时,计算类属性可以在子类中被重写 -
extension中可以定义计算类属性
3、属性观察者
属性观察者会观察用来观察属性值的变化,一个 willSet 当属性将被改变调用,即使这个值与原有的值相同,而 didSet 在属性已经改变之后调用。它们的语法类似于 getter 和 setter。
-
willSet观察器会将新的属性值作为常量参数传入,在willSet的实现代码中可以为这个参数指定一个名称,如果不指定则参数仍然可用,这时使用默认名称newValue表示。 -
didSet观察器会将旧的属性值作为参数传入,可以为该参数命名或者使用默认参数名oldValue。如果在didSet方法中再次对该属性赋值,那么新值会覆盖旧的值。var name:String {
willSet { print("(newValue)")
}
didSet {
print("(oldValue)") } }
三、延迟存储属性
- 用关键字
lazy来标识一个延迟存储属性 - 必须将延迟存储属性声明成变量(使用
var关键字),因为属性的初始值可能在实例构造完成之后才会得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性 - 延迟存储属性的初始值在其第一次使用时才进行计算