10.属性 Properties Swift官方文档——版纳的笔

2018-03-28  本文已影响0人  KevinFromChina
//: Playground - noun: a place where people can play

import UIKit

// # 存储属性
// 存储属性会存储常量或变量作为实例的一部分,存储属性只能由类和结构体定义。
struct FixedLengthRange {
    var firstValue: Int
    let length: Int
}
// 没有默认的初始化器,但是有默认的赋值初始化器
var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
// 延迟存储属性在其第一次使用时才进行计算.而且必须是var.作用:提高效率,有时是必须这样才能解决问题***
class LazyDemo {
    var b = 0
    var c = 3
    lazy var a = FixedLengthRange(firstValue: b, length: c)
    
}
// 若不加lazy会报错: property initializers run before 'self' is available. 加上lazy就得到完美解决
// 如果被标记为 lazy 修饰符的属性同时被多个线程访问并且属性还没有被初始化,则无法保证属性只初始化一次。???

// # 计算属性
// 计算属性会计算(而不是存储)值,计算属性可以由类、结构体和枚举定义。注意:计算属性必须用var定义,不管是不是只读属性.计算属性也是延迟的,所以可以在定义阶段恣意调用类中的属性***
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(newCenter) {
            origin.x = newCenter.x - (size.width / 2)
            origin.y = newCenter.y - (size.height / 2)
        }// 计算属性本身并不存储,所以set中,没有任何值存储,只是实例中的origin属性被改变了,(newCenter)可以不要,有一个默认的newValue可以代替newCenter使用
    }
}
var square = Rect(origin: Point(), size: Size(width: 10, height: 10))
let initialSquareCenter = square.center
square.center = Point(x: 15, y: 15)
print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
// 只读属性,没有setter只有getter.而且可以简写

// # 属性观察者
// 每当一个属性的值被设置时,属性观察者都会被调用,即使这个值与该属性当前的值相同。
// 可以为任意存储属性添加属性观察者,除了延迟存储属性。也可以通过在子类里重写属性来为任何继承属性(无论是存储属性还是计算属性)添加属性观察者。不需要为非重写的计算属性定义属性观察者,因为可以在计算属性的设置器里直接观察和响应它们值的改变。
// 父类属性的 willSet 和 didSet 观察者会在子类初始化器中设置时被调用***。它们不会在类的父类初始化器调用中设置其自身属性时被调用。***
class StepCounter {
    var totalSteps: Int = 0 {
        willSet(newTotalSteps) { // 可以不要命名,函数体中使用newValue即可
            print("About to set totalSteps to \(newTotalSteps)")
        }
        didSet {
            if totalSteps > oldValue {
                print("Added \(totalSteps - oldValue) steps")
            }
        }
    }
    init(rawSteps: Int) {
        totalSteps = rawSteps
    }
}
let stepCounter = StepCounter(rawSteps: 20)
stepCounter.totalSteps = 200
// 如果你以输入输出形式参数传一个拥有观察者的属性给函数, willSet 和 didSet 观察者一定会被调用。这是由于输入输出形式参数的拷贝入拷贝出存储模型导致的:值一定会在函数结束后写回属性。***

// # 全局和局部变量
// 全局变量是定义在任何函数、方法、闭包或者类型环境之外的变量。局部变量是定义在函数、方法或者闭包环境之中的变量。
// 全局常量和变量永远是延迟计算的,与延迟存储属性有着相同的行为。不同于延迟存储属性,全局常量和变量不需要标记 lazy 修饰符
var a = 0 {
    didSet {
        print("a's old value is \(oldValue)")
    }
}
a += 1

// # 类型属性
// 实例属性是属于某个类型实例的属性。每次创建这个类型的新实例,它就拥有一堆属性值,与其他实例不同。
struct SomeStructure {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 1
    }
}
enum SomeEnumeration { // trick: 这个enum没有定义自己的成员,但是有类型属性
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 6
    }
}
// 以上static的属性都不能被子类重写.要允许重写并且属性是计算属性,标注class关键字.
class Dream {
    class var text: String {
        return "A sweet one."
    }
}
class SpecificDream: Dream {
    static var earlyYear = 0
    override class var text: String {
        return "A sweet one since \(earlyYear)"
    }
}

// 不同于存储实例属性,你必须总是给存储类型属性一个默认值。这是因为类型本身不能拥有能够在初始化时给存储类型属性赋值的初始化器。
// 存储类型属性是在它们第一次访问时延迟初始化的。但是只初始化一次.
class SomeClass {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 27
    }
    class var overrideableComputedTypeProperty: Int {
        return 107
    }
}
print(SomeStructure.storedTypeProperty)
SomeStructure.storedTypeProperty = "Another value."
print(SomeStructure.storedTypeProperty)
print(SomeEnumeration.computedTypeProperty)
struct AudioChannel {
    static let thresholdLevel = 10
    static var maxInputLevelForAllChannels = 0
    var currentLevel: Int = 0 {
        didSet {
            if currentLevel > AudioChannel.thresholdLevel {
                // cap the new audio level to the threshold level
                currentLevel = AudioChannel.thresholdLevel
            }
            if currentLevel > AudioChannel.maxInputLevelForAllChannels {
                // store this as the new overall maximum input level
                // 成为目前为止所有AudioChannel实例的最大值
                AudioChannel.maxInputLevelForAllChannels = currentLevel
            }
        }
    }
}
// 类型属性可以在任何地方访问.
上一篇下一篇

猜你喜欢

热点阅读