本节知识点
- 存储属性
- 常量存储属性
- 类和结构体常量与存储属性的关系
- 延迟存储(懒加载)属性
- 计算属性
- 只读计算属性
- 类属性
- 属性观察器
1. 存储属性
- Swift中的存储属性就是以前学习OC中的普通属性
- 在结构体或者类中定义的属性, 默认就是存储属性
struct Person {
var name: String
var age: Int
}
var p:Person = Person(name: "cdh", age: 20)
p.name = "CDH"
p.age = 50
2. 常量存储属性
- 常量存储属性只能在定义时或构造时修改
- 构造好一个对象之后不能对常量存储属性进行修改
struct Person1 {
var name: String
var age: Int
let card: String // 身份证
}
var p1: Person1 = Person1(name: "cdh", age: 20, card: "123456")
p1.name = "CDH"
p1.age = 50
//构造好对象之后不能修改常量存储属性
//以下写法是错误的
//p1.card = "56789"
3. 类和结构体常量与存储属性的关系
-
类是引用类型
- 可以修改类常量中属性的值, 因为他指向的对象不是一个常量
-
结构体和枚举是值类型
- 因此不能修改结构体常量中的属性
- 不能修改结构体/枚举常量对象中的值, 因为他指向的对象是一个常量
class Person3 {
var name: String = "cdh"
var age: Int = 20
}
let p3:Person3 = Person3()
//可以修改类常量中属性的值, 因为他指向的对象不是一个常量
p3.name = "CDH"
//不可以修改类常量的指向
//以下写法是错误的
//p3 = Person4()
struct Person2 {
var name: String
var age: Int
}
let p2: Person2 = Person2(name: "cdh", age: 20)
//因为结构体是值类型, 所以不能修改结构体常量中的属性
//不能修改结构体/枚举常量对象中的值, 因为他指向的对象是一个常量
//以下写法错误
//p2.name = "CDH" //不能修改结构体常量对象的值
//以下写法错误
//p2 = Person2(name: "CDH", age: 50)
4. 延迟存储(懒加载)属性
- Swift语言中所有的存储属性必须有初始值, 也就是当构造完一个对象后, 对象中所有的存储属性必须有初始值
- 但是也有例外, 其中延迟存储属性可以将属性的初始化推迟到该属性第一次被调用的时候
- 这个延时属性对应于 OC 中的懒加载的概念
- 苹果的设计思想:希望所有的对象在使用时才真正加载到内存中
- 和OC不同的是 Swift 有专门的关键字来实现懒加载
-
lazy
关键字可以用于定义某一个属性懒加载
lazy var 变量: 类型 = { 创建变量代码 }()
// 懒加载也就是闭包, 尾巴的小括号()表示执行闭包
- 懒加载的好处
- 多次使用只要内存有一次加载, 并且内存中一直存在就不会重复加载
class Line {
var start:Double = 0.0
var end: Double = 0.0
// 如果不是lazy属性,定义的时候对象还没有初始化,所以不能访问self
// 如果加上lazy,代表使用时才会加载,也就是使用到length属性时才会调用self
// 而访问一个类的属性必须通过对象方法
// 所以访问时对象已经初始化完成了,可以使用self
lazy var length: Double = self.getLenght()
// 通过闭包懒加载
lazy var container: Array<AnyObject> = {
print("懒加载")
var arrM = []
return arrM as [AnyObject]
}()
func getLenght() ->Double
{
print("懒加载")
return end - start
}
}
var line = Line()
line.end = 150.0
print("创建对象完毕")
print(line.length)
var arrM = line.container
arrM.append("1")
arrM.append(5)
print(arrM)
//输出结果:
//创建对象完毕
//懒加载
//150.0
//懒加载
//[1, 5]
5. 计算属性
- 1.Swift中的计算属性不直接存储值
- 2.计算属性用于计算, 可以实现setter和getter这两种计算方法
- 3.枚举不可以有存储属性, 但是允许有计算属性
- setter 对象.属性 = 值
- getter var value = 对象.属性
struct Rect {
var origion: (x: Double, y: Double) = (0, 0)
var size: (w: Double, h: Double) = (0, 0)
// 由于center的值是通过起点和宽高计算出来的, 所以没有必要提供一个存储属性
var center: (x: Double, y: Double) {
get{
return (origion.x + size.w/2, origion.y + size.h/2)
}
set{
// 注意: 计算属性不具备存储功能, 所以不能给计算属性赋值
// 如果赋值会发生运行时错误
// 注意: setter可以自己传递一个参数, 也可以使用系统默认的参数newValue
// 如果要使用系统自带的参数, 必须删除自定义参数
origion.x = newValue.x - size.w / 2
origion.y = newValue.y - size.h / 2
}
}
}
var r = Rect()
r.origion = (0, 0)
r.size = (100, 100)
print("center.x = \(r.center.x) center.y = \(r.center.y)")
//输出结果: center.x = 50.0 center.y = 50.0
r.center = (100, 100)
print("origion.x = \(r.origion.x) origion.y = \(r.origion.y)")
//输出结果: origion.x = 50.0 origion.y = 50.0
print("center.x = \(r.center.x) center.y = \(r.center.y)")
//输出结果:center.x = 100.0 center.y = 100.0
6. 只读计算属性
- 对应OC中的readonly属性
- 所谓的只读属性就是只提供了getter方法, 没有提供setter方法
class Line1 {
var start:Double = 0.0
var end: Double = 0.0
// 只读属性, 只读属性必须是变量var, 不能是常量let
// 例如想获取长度
// 只能通过计算获得, 而不需要外界设置, 可以设置为只读计算属性
var length: Double{
// 只读属性的简写, 可以省略get{}
return end - start
}
}
var line1 = Line1()
line1.end = 100
print(line1.length)
//输出结果: 100.0
7. 类属性
- 在结构体和枚举中用static
- 在类中使用class, 并且类中不允许将存储属性设置为类属性
struct Person4 {
// 普通的属性是每个对象一份
var name: String = "cdh"
// 类属性是所有相同类对象共用一份
static var gender:String = "man"
static var age:Int{
return 20
}
func show()
{
print("gender = \(Person4.gender) name = \(name)")
}
}
var p4 = Person4()
print("gender = \(Person4.gender)")
//输出结果: gender = man
var p5 = Person4()
//类属性是所有对象共用一份
print("gender = \(Person4.gender)")
p5.show()
//输出结果:
//gender = man
//gender = man name = cdh
//可以将计算属性设置为类属性
print("age = \(Person4.age)")
//输出结果:age = 20
class Person5 {
// 普通的属性是每个对象一份
var name: String = "cdh"
// 类中不允许将存储属性定义为类属性
// 下面为错误写法
// class var gender:String = "man"
// 类中只能将计算属性定义为类属性
class var age:Int{
return 20
}
func show()
{
print("age = \(Person5.age)")
}
}
var p6 = Person5()
print("age = \(Person5.age)")
p6.show()
//输出结果:
//age = 20
//age = 20
8. 属性观察器
- 类似OC中的KVO
- 可以用于监听属性什么时候被修改, 只有属性被修改才会调用
- 有两种属性观察器:
- 1.willSet, 在设置新值之前调用
- 2.didSet, 在设置新值之后调用
- 可以直接为除计算属性和lazy属性之外的存储属性添加属性观察器
- 但是可以在继承类中为父类的计算属性提供属性观察器
- 因为在计算属性中也可以监听到属性的改变
- 所以给计算属性添加属性观察器没有任何意义
class Line2 {
var start:Double = 0.0{
willSet{
print("willSet newValue = \(newValue)")
}
didSet{
print("didSet oldValue = \(oldValue)")
}
}
var end: Double = 0.0
}
var l2 = Line2()
l2.start = 10.0
//输出结果:
//willSet newValue = 10.0
//didSet oldValue = 0.0