swift中跟实例相关的属性可以分为2大类。
1. 存储属性(Stored Property)
1.1 相当于成员变量的概念;
1.2 存储在实例的内存中;
1.3 结构体和类可以定义存储属性;
1.4 枚举【不可以】定义存储属性;2. 计算属性(Computed Property)
2.1 本质就是方法(函数);
2.2 不占用实例的内存;
2.3 枚举、结构体、类都可以定义计算属性;struct Circle { //存储属性-半径 var radius : Double //计算属性-直径 var diameter : Double { set{ radius = newValue / 2 } get { radius * 2 } } }
1.存储属性(Stored Property)
存储属性可以是变量存储属性(用关键字var定义),也可以是常量存储属性(用关键字let定义)。
在创建【类】或【结构体】的实例时,必须为所有的存储属性设置一个合适的初始值。
【 例:】
解决这个报错,有以下几种方法
【 方法一:】 可以再初始化器里为存储属性设置一个初始值;struct Point { var x: Int var y: Int init() { x = 10 y = 20 } } var p1 = Point()
【 方法二:】 可以分配一个默认的属性作为属性定义的一部分
struct Point { var x: Int = 10 var y: Int = 20 } var p1 = Point()
2. 计算属性(Computed Property)
计算属性不直接存储值,而是提供一个 getter 来获取值,一个可选的 setter 来间接设置其他属性或变量的值。
如果计算属性的 setter 没有定义表示新值的参数名,则可以使用默认名称 newValue。
【 例:】
struct Circle { //存储属性-半径 var radius : Double //计算属性-直径 var diameter : Double { set{ radius = newValue / 2 } get { radius * 2 } } }
【 只读计算属性】
只有 getter 没有 setter 的计算属性就是只读计算属性。
【 例:】struct Circle { //存储属性-半径 var radius : Double //计算属性-直径 var diameter : Double { get { radius * 2 } } }
【注意】
① 只读计算属性总是返回一个值,可以通过点(.)运算符访问,但不能设置新的值。
② 不能只有set 而没有get
* 拓展
【 延迟存储属性(Lazy Stored Property) 】
延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。
在属性声明前使用 lazy 来标示一个延迟存储属性。
【 例1:】
lazy var car = Car()
class Car { init() { print("Car init") } func run() -> Void { print("Car is running~") } } class Person { lazy var car = Car() init() { print("Person init!") } func goOut() -> Void { car.run() } } let p = Person() print("----------") p.goOut()
输出结果如下:
Person init! ---------- Car init Car is running~
根据输出结果我们得知,当我们创建Person对象的时候,
let p = Person()
,暂时没有用到car的属性,所以不会调用car的初始化方法,此时只会打印Person init!
语句,和----------
,接着会执行p.goOut()
,因为goOut()里面有car对象,所以此时会调用car对象的初始化方法,打印Car init
和Car is running~
【 例2:】
var car = Car() 没有lazy属性修饰
class Car { init() { print("Car init") } func run() -> Void { print("Car is running~") } } class Person { var car = Car() init() { print("Person init!") } func goOut() -> Void { car.run() } } let p = Person() print("----------") p.goOut()
输出结果如下:
Car init Person init! ---------- Car is running~
由两个例子对比我们可以知道,lazy修饰的对象,可以延迟对象的创建
注意:
必须将延迟存储属性声明成变量
(使用var
关键字),因为属性的值在实例构造完成之前可能无法得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。
【 属性观察器( Property Observer) 】
可以为除了延迟存储属性(非lazy)之外的其他存储属性添加属性观察器.
【 例:】
struct Circle { //存储属性-半径 var radius : Double { willSet { print("willSet",newValue) } didSet { print("didSet",oldValue,radius) } } init() { self.radius = 1.0 print("Circle init~~") } } var circle = Circle() circle.radius = 5.5 print(circle.radius)
运行结果如下:
Circle init! willSet 5.5 didSet 1.0 5.5 5.5
【 小结:】
可以为属性添加如下的一个或全部观察器:① willSet在设置新的值之前调用,默认交newValue
② didSet在新的值被设置之后立即调用,默认叫oldValue
③willSet和didSet观察器在属性初始化器过程中不会被调用
【 全局变量和局部变量 】
属性观察器、计算属性功能 ,同样可用于全局变量、局部变量。
① 全局属性
///全局属性 var number: Int { get { return 10 } set { print("setNumber",newValue) } } number = 20 //setNumber 20 print(number) //getNumber 10
② 局部属性
///局部属性 func testFunc() { var age = 10 { willSet { print("willSet",newValue) } didSet { print("didSet",oldValue,age) } } age = 11 //willSet 11 //willSet 10 11 } testFunc()
【 类型属性( Type Property) 】
使用关键字 static 来定义值类型的类型属性,关键字 class 来为类定义类型属性。
使用static修饰
static var count : Int = 0
- 类型属性(Type Property)只能通过类型去访问
① 存储类型属性(Stored Type Property):整个程序运行过程中,只有一份内存(类似于全局变量),
存储类型属性默认是lazy,会在第一次使用的时候才初始化;
② 计算类型属性(Computed Type Property)
- 可以通过static定义属性类型
【 例:】struct Shape { var width : Int = 0 static var count : Int = 0 } var s = Shape() Shape.count = 10 print(Shape.count)
- 如果是类,可以用关键字class
【 例:】class Shape { var width : Int = 0 class var count : Int { return 0 } } var s = Shape() print(Shape.count)
【 小结:】
1.如果是struct定义的类型,使用class来修饰是不可以的,会报错,只能用static来修饰正确的写法: