天天看點

Swift 屬性(九)

屬性 (Properties)

1.存儲屬性

存儲在類或結構體的執行個體中的一個變量或常量,可以在定義的時候指派,也可以在構造過程時候指派

// length定義為常量,在建立執行個體的時候指派,之後就無法再修改了
struct FixedLengthRange {
    var firstValue: Int
    let length: Int
}
var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
// the range represents integer values 0, 1, and 2
rangeOfThreeItems.firstValue = 6
// the range now represents integer values 6, 7, and 8
           

2.常量

建立一個結構體的執行個體并指派給一個常量,就無法再修改執行個體的任何屬性了,即使有定義變量屬性,因為結構體屬于值類型,當值類型的執行個體被聲明為常量的時候,所有的屬性也就成了常量,跟引用類型的類不一樣,類指派給常量後,仍然可以修改執行個體的屬性

let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
// this range represents integer values 0, 1, 2, and 3
rangeOfFourItems.firstValue = 6
// this will report an error, even thought firstValue is a variable property
           

3.延遲存儲屬性

當第一次被調用的時候才會計算其初始值,使用@lazy标志,屬性的值在執行個體構造完成之前可能為空,而常量要求構造完成之前必須有初始值,是以延遲屬性必須是變量

// DataImporter在初始化的時候需要消耗不少時間,因為可能要打開檔案并讀取檔案内容,是以在建立DataManager的時候不需要建立DataImporter執行個體,而是當用到才建立
class DataImporter {
    /*
    DataImporter is a class to import data from an external file.
    The class is assumed to take a non-trivial amount of time to initialize.
    */
    var fileName = "data.txt"
    // the DataImporter class would provide data importing functionality here
}
 
class DataManager {
    @lazy var importer = DataImporter()
    var data = String[]()
    // the DataManager class would provide data management functionality here
}
 
let manager = DataManager()
manager.data += "Some data"
manager.data += "Some more data"
// the DataImporter instance for the importer property has not yet been created
           

4.計算屬性

計算屬性不直接存儲值,提供一個getter來擷取,可選的setter來設定

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)
    }
    }
}
var square = Rect(origin: Point(x: 0.0, y: 0.0),
    size: Size(width: 10.0, height: 10.0))
let initialSquareCenter = square.center
square.center = Point(x: 15.0, y: 15.0)
println("square.origin is now at (\(square.origin.x), \(square.origin.y))")
// prints "square.origin is now at (10.0, 10.0)"
           

5.便捷setter聲明

如果setter沒有定義參數名,則使用預設名稱 newValue

struct AlternativeRect {
    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)
    }
    }
}
           

6.隻讀計算屬性

隻有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)
println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
// prints "the volume of fourByFiveByTwo is 40.0"
           

7.屬性螢幕

監控屬性值的變化,在屬性被設定新值的時候調用,即使新值與原有相同,可以為延遲屬性添加螢幕,不需要為無法重載的計算屬性添加螢幕,因為可以通過setter直接監控

wilSet 在設定新值前調用
didSet 新的值被設定後調用
willSet會将新值作為固定參數傳入,如果不指定參數,預設使用newValue,didSet會将就值作為參數傳入,不指定的話預設參數名為oldValue,如果在didSet螢幕為屬性設值,那這個值會替換螢幕之前設定的值

willSet和didSet螢幕不會在屬性初始化的時候調用,隻會在屬性初始化之後的其他地方比如被設定的時候調用

class StepCounter {
    var totalSteps: Int = 0 {
    willSet(newTotalSteps) {
        println("About to set totalSteps to \(newTotalSteps)")
    }
    didSet {
        if totalSteps > oldValue  {
            println("Added \(totalSteps - oldValue) steps")
        }
    }
    }
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
// About to set totalSteps to 200
// Added 200 steps
stepCounter.totalSteps = 360
// About to set totalSteps to 360
// Added 160 steps
stepCounter.totalSteps = 896
// About to set totalSteps to 896
// Added 536 steps
           

8.全局變量和局部變量

全局變量是相對于全局的,在函數,方法,閉包或任何類型之外定義的變量,局部變量是在函數,方法或閉包内部定義的變量,全局變量跟延遲存儲屬性一樣,但不需要@lazy修飾

9.類型屬性

類型屬性文法

使用關鍵字static定義值類型的類型屬性,class定義類

struct SomeStructure {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
    // return an Int value here
    }
}
enum SomeEnumeration {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
    // return an Int value here
    }
}
class SomeClass {
    class var computedTypeProperty: Int {
    // return an Int value here
    }
}
           

擷取和設定類型屬性的值

類型屬性的通路是通過點運算符操作

println(SomeClass.computedTypeProperty)
// prints "42"
 
println(SomeStructure.storedTypeProperty)
// prints "Some value."
SomeStructure.storedTypeProperty = "Another value."
println(SomeStructure.storedTypeProperty)
// prints "Another value."
           

以下是另一個比較完整的例子

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.maxInputLevelForAllChannels = currentLevel
        }
    }
    }
}

var leftChannel = AudioChannel()
var rightChannel = AudioChannel()

leftChannel.currentLevel = 7
println(leftChannel.currentLevel)
// prints "7"
println(AudioChannel.maxInputLevelForAllChannels)
// prints "7"

rightChannel.currentLevel = 11
println(rightChannel.currentLevel)
// prints "10"
println(AudioChannel.maxInputLevelForAllChannels)
// prints "10"