学习swift从青铜到王者之swift属性09

1.结构体常量和类常量的存储属性

let p1 = Person1()
//p1.age = 88 不允许修改
//p11.name = "yhx1" 不允许修改

var p11 = Person1()
p11.age = 88
//p11.name = "yhx1"  不允许改变


class Person2{
    let name: String = "yhx"
    var age: Int = 8
}
let p2 = Person2()
//p2.name = "yhx1" 不允许修改
p2.age = 88

var p22 = Person2()
//p22.name = "yhx1" 不允许修改
p22.age = 88
/*总结:
1.如果你创建一个结构体实例并且把实例赋值给一个常量,你不能够修改这个常量的属性,即使这些属性是变量。
2.这是因为,结构体是值类型,当一个值类型的实例被标记为敞亮的时候,它的所有属性都将是常量。
3.相同的情况对于类却不同,因为类实例是引用类型。如果你把类实例赋值给一个常量的话,你依然可以改变他的变量属性的值。
*/

2.延迟存储属性

/**
 (4)延迟存储属性
 Swift语言中所有的存储属性必须有初始值,也就是当构造完一个类或者结构体的对象后;
 对象中所有的存储属性必须有初始值(这是这个语言要求的),但是也有例外,
 其中延迟存储属性可以将属性的初始化向后推迟到该属性第一次被调用的时候。
 
 1.这个属性不适合一开始初始化,取决于外部的很多因素;
 2.属性有可能我们从来不用,但是它的初始化又需要较长时间;
 必须将延迟存储属性声明成变量(使用var关键字),因为属性的值在实例构造完成之前可能无法得到。
 而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。
 */

struct MyStudent {
    var name: String
    var chinese: Double
    var math: Double
    
    func showMySelf() -> Void {
        print("姓名:\(name), 语文成绩:\(chinese), 数学成绩:\(math)")
    }
}

class MyClass {
    var members:[MyStudent] = []
    // 班级里面所有学生的平均成绩
    // 按照该语言的特性,这里必须要有一个初始值,但是我们一开始没办法知道平均成绩的值
    // 给它一个初始值0,也没有意义,不是真实的成绩。那么这里我们把它设为延迟存储属性lazy。
    lazy var score: Double = MyClass().getScore()
    
    func getScore() -> Double {
        
        print("test lazy property")
        var t: Double = 0.0
        
        for i in members {
            t += i.chinese
            t += i.math
        }
        
        if members.count > 0 {
            return t / Double(members.count)
        } else {
            return 0
        }
    }
    
    func show() -> Void {
        for i in members {
            i.showMySelf()
        }
    }
}

let s0 = MyStudent.init(name: "zhangsan", chinese: 100.0, math: 100.0)
let s1 = MyStudent.init(name: "lisi", chinese: 90.0, math: 90.0)

let c0 = MyClass.init()
c0.members.append(s0)
c0.members.append(s1)
c0.show()
//print(c0.getScore())

print("***********************")
// 我们看到打印 test lazy property了
print(c0.score)

3.属性观察器

/**
 属性观察器
 观察属性的变化,是指属性被修改时可以调用我们事先写好的代码去额外执行一些操作。
 类似于OC中的KVO
 
 存在两种属性观察器
 1. willSet 在设置新值的时候调用
 2. didSet  在设置新值的之后调用
 可以直接为除 lazy属性之外的存储属性添加属性观察器,你不可以直接给类里面的计算属性添加属性观察器,
 当然也可以在继承类中为父类的计算属性提供属性观察器。
 */
struct MyRect {
    var origion:(x: Double, y: Double) = (0, 0) {
        willSet {
            // 属性被修改之前
            print("will set==\(newValue.x)  \(newValue.y)")
        }
        
        didSet {
            // 属性被修改之后
            print("did set==\(oldValue.x)  \(oldValue.y)")
        }
    }
    var size: (w: Double, h: Double) = (0, 0)
    var center: (x: Double, y: Double) = (0, 0)
}
var rect = MyRect()
rect.size = (100, 100)
// 写  内容被修改的时候被调用
rect.origion = (9, 9) // setter 写
// 这个时候不会调用了
let ddd = rect.origion // getter 读
rect.center = (rect.origion.x + rect.size.w / 2, rect.origion.y + rect.size.h / 2)

posted on 2017-12-08 17:01  jack_yan  阅读(187)  评论(0编辑  收藏  举报