010-Swift3.0之属性

一、存储属性

存储属性就是存储在特定类或结构体实例里的一个常量或变量

存储属性可以是变量(var)存储属性,也可以是常量(let)存储属性

1.结构体对象的存储属性--值类型

1)变量结构体对象的存储属性

struct AA {
    var firstValue: Int     // 变量存储属性
    let length: Int          // 常量存储属性
}
var aa = AA(firstValue: 0, length: 3)
aa.firstValue = 10
// aa.length = 3   // 报错,length为常量存储属性,值不可变

2)常量结构体对象的存储属性

由于结构体是值类型,所以对于常量结构对象来讲,其任何属性值(不论常量变量)均不可变

结构体对象中的每个属性都是结构体对象的值,常量结构体对象的值均是不可变的

struct AA {
    var firstValue: Int     // 变量存储属性
    let length: Int          // 常量存储属性
}
let bb = AA(firstValue: 6, length: 3)
// bb.firstValue = 7  // 报错,bb为常量结构体,所以其任何属性值均不可变
// bb.length = 2   // 报错,bb为常量结构体,所以其任何属性值均不可变

2.类对象的存储属性

1)变量类对象的存储属性

class BB {
    var firstValue: Int = 0  // 变量存储属性
    let length: Int = 3        // 常量存储属性
}
var aaa = BB()
aaa.firstValue = 20
// aaa.length = 10  // 报错,length为常量存储属性,值不可变

2)常量类对象的存储属性

由于类是引用类型,所以对于常量类对象来讲,其变量属性还是可变的,但是常量属性是不可变的

类对象在Swift中相当于是一个指针,常量类对象,就相当于这个指针的指向地址是不可以发生改变,但是其指向的空间里的内容还是可以根据是否是变量来决定是否可变的

class BB {
    var firstValue: Int = 0  // 变量存储属性
    let length: Int = 3        // 常量存储属性
}
let bbb = BB()
bbb.firstValue = 12   // 没有报错,因为指向空间里的变量属性firstValue可发生改变
// bbb.length = 4  // 报错,是因为length是常量属性

3.延迟存储属性

延迟存储属性是指当第一次被调用的时候才去初始化计算属性值的属性

在属性声明前使用lazy来标识一个延迟存储属性

延迟存储属性必须声明成变量(var),因为常量属性在构造过程完成之前必须要有初始值

延迟属性只有在第一次调用时,才会去初始化计算其初始值

注意:延迟性属性在没有初始化时就同时被多个线程访问,则无法保证该属性只会被初始化一次

class DataImporter {
    // 该类负责将外部文件中的数据导入,这个类的初始化会消耗不少时间
    var fileName = "data.txt"
}
class DataManager {
    lazy var importer = DataImporter()  // 延迟属性
    var data = [String]()
}
let manager = DataManager()
manager.importer // 延迟性属性importer只有在第一次调用的时候才会去计算初始值
class MyRange {
    let start: Int
    let end: Int
    var width: Int {
        return end - start + 1
    }
    
    // 延迟属性
    // 这个闭包里面的计算过程只会在第一次调用sum属性时调用,后面都不会调用
    lazy var sum: Int = {
        var res = 0
        for i in self.start ... self.end {
            res += i
        }
        return res
    }()
    
    init?(start: Int, end: Int) {
        if start > end {
            return nil
        }
        self.start = start
        self.end = end
    }
}
let myRange = MyRange(start: 0, end: 4)
if let myRange = myRange {
    myRange.sum
    myRange.sum
    myRange.sum
}

 

二、计算属性

计算属性不直接存储值,而是提供一个getter和一个可选的setter,来间接获取和设置其他属性或变量的值

注意:必须使用var定义计算属性,因为它们的值不是固定的

1.计算属性

struct Point {
    var x = 0.0, y = 0.0
}
struct Size {
    var width = 0.0, height = 0.0
}
struct Rect {
    var origin = Point()
    var size = Size()
    // 计算属性
    var center: Point {
        get {
            let centerX = origin.x + (size.width / 2)
            let centerY = origin.y + (size.height / 2)
            return Point(x: centerX, y: centerY)
        }
        // 注意:这里可以自命名参数
        set {
            origin.x = newValue.x - (size.width / 2)
            origin.y = newValue.y - (size.height / 2)
        }
    }
}
var square = Rect(origin: Point(x: 0.0, y: 0.0), size: Size(width: 10.0, height: 10.0))
let initialSquareCenter = square.center  // 会调用计算属性center的get方法获取最新值
square.center = Point(x: 15.0, y: 15.0) // 会调用计算属性center的set方法重新设置起点坐标
print("起点坐标:(\(square.origin.x), \(square.origin.y))")  // 起点坐标:(10, 10)

2.只读计算属性

只有getter没有setter的计算属性就是只读计算属性

只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值

struct Cuboid {
    var width = 0.0, height = 0.0, depth = 0.0
    // 只读计算属性,只能获取其属性值,不可以直接设置
    var volume: Double {
        return width * height * depth
    }
}
let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
let volume = fourByFiveByTwo.volume  // 会调用计算属性volume的get方法获取最新值
// fourByFiveByTwo.volume = 20  // 报错,因为是只读属性,没有set方法

 

三、属性观察器

属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,即使新值和当前值相同的时候也不例外

可以为属性添加如下的一个或全部观察器:

willSet在新的值被设置之前调用

didSet在新的值被设置之后立即调用

class StepCounter {
    var totalSteps: Int = 0 {
        willSet {
            print("属性totalSteps新的值为:\(newValue)")
        }
        didSet {
            if totalSteps > oldValue  {
                print("属性totalSteps新值与旧值之差为:\(totalSteps - oldValue)")
            }
        }
    }
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
// 属性totalSteps新的值为:200
// 属性totalSteps新值与旧值之差为:200
stepCounter.totalSteps = 360
// 属性totalSteps新的值为:360
// 属性totalSteps新值与旧值之差为:160
stepCounter.totalSteps = 896
// 属性totalSteps新的值为:896
// 属性totalSteps新值与旧值之差为:536

 

四、类型属性

类型属性用关键字static修饰

class Player {
    var name: String
    var score = 0
    static var highestScore = 0    // 类型属性

    init(name: String) {
        self.name = name
    }

    func play() {
        let score = 100
        print("\(name)的得分是:\(score)")

        // 注意:这里的self指的是实例对象,因为play()这个方法是实例对象调用的方法
        self.score += score
        print("\(name)的总分是:\(self.score)")

        // 注意:highestScore是类型属性,也就是是Player这个类的属性
        if self.score > Player.highestScore {
            Player.highestScore = self.score
        }
    }
}

 

posted @ 2017-03-24 14:55  Frank9098  阅读(102)  评论(0)    收藏  举报