10.屬性 Properties Swift官方文檔——版納的筆記

//: 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定義,不管是不是只讀屬性.計算屬性也是延遲的,所以可以在定義階段恣意調(diào)用類中的屬性***
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.而且可以簡寫

// # 屬性觀察者
// 每當一個屬性的值被設置時,屬性觀察者都會被調(diào)用,即使這個值與該屬性當前的值相同。
// 可以為任意存儲屬性添加屬性觀察者,除了延遲存儲屬性。也可以通過在子類里重寫屬性來為任何繼承屬性(無論是存儲屬性還是計算屬性)添加屬性觀察者。不需要為非重寫的計算屬性定義屬性觀察者,因為可以在計算屬性的設置器里直接觀察和響應它們值的改變。
// 父類屬性的 willSet 和 didSet 觀察者會在子類初始化器中設置時被調(diào)用***。它們不會在類的父類初始化器調(diào)用中設置其自身屬性時被調(diào)用。***
class StepCounter {
    var totalSteps: Int = 0 {
        willSet(newTotalSteps) { // 可以不要命名,函數(shù)體中使用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
// 如果你以輸入輸出形式參數(shù)傳一個擁有觀察者的屬性給函數(shù), willSet 和 didSet 觀察者一定會被調(diào)用。這是由于輸入輸出形式參數(shù)的拷貝入拷貝出存儲模型導致的:值一定會在函數(shù)結束后寫回屬性。***

// # 全局和局部變量
// 全局變量是定義在任何函數(shù)、方法、閉包或者類型環(huán)境之外的變量。局部變量是定義在函數(shù)、方法或者閉包環(huán)境之中的變量。
// 全局常量和變量永遠是延遲計算的,與延遲存儲屬性有著相同的行為。不同于延遲存儲屬性,全局常量和變量不需要標記 lazy 修飾符
var a = 0 {
    didSet {
        print("a's old value is \(oldValue)")
    }
}
a += 1

// # 類型屬性
// 實例屬性是屬于某個類型實例的屬性。每次創(chuàng)建這個類型的新實例,它就擁有一堆屬性值,與其他實例不同。
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
            }
        }
    }
}
// 類型屬性可以在任何地方訪問.
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容