1. 相比較於Java,Swift中屬性頗有意思,有不少分類:存儲屬性、計算屬性和類型屬性等等。app
2. 存儲屬性spa
存儲屬性:一個存儲屬性就是存儲在特定類或結構體的實例裏的一個常量或變量,存儲屬性能夠是變量存儲屬性(用關鍵字var
定義),也能夠是常量存儲屬性(用關鍵字let
定義)。code
若是建立了一個結構體的實例並賦值給一個常量,則沒法修改實例的任何屬性,即便定義了變量存儲屬性,代碼以下:blog
let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4) // 該區間表示整數0,1,2,3 rangeOfFourItems.firstValue = 6 // 儘管 firstValue 是個變量屬性,這裏仍是會報錯
2.1 延遲存儲屬性get
延遲存儲屬性是指當第一次被調用的時候纔會計算其初始值的屬性。在屬性聲明前使用lazy
來標示一個延遲存儲屬性。必須將延遲存儲屬性聲明成變量(使用var
關鍵字),由於屬性的值在實例構造完成以前可能沒法獲得。而常量屬性在構造過程完成以前必需要有初始值,所以沒法聲明成延遲屬性。it
當屬性的值依賴於在實例的構造過程結束前沒法知道具體值的外部因素時,或者當屬性的值須要複雜或大量計算時,能夠只在須要的時候來計算它,這時候咱們可使用延遲存儲屬性。代碼以下:io
class DataImporter { var fileName = "data.txt" } class DataManager { lazy var importer = DataImporter() var data = [String]() } let manager = DataManager() manager.data.append(" new data")
imprter 前面的關鍵字是lazy,是延遲存儲屬性,DataManager
也可能不從文件中導入數據。因此當DataManager
的實例被建立時,不必建立一個DataImporter
的實例,更明智的是當用到DataImporter
的時候纔去建立它。class
2.2 計算屬性import
除存儲屬性外,類、結構體和枚舉能夠定義計算屬性,計算屬性不直接存儲值,而是提供一個 getter 來獲取值,一個可選的 setter 來間接設置其餘屬性或變量的值。代碼以下:監控
struct Point { var x = 0.0 , y = 0.0 } struct Size { var width = 0.0 , height = 0.0 } struct Rec { 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 = Rec(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) print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
Rec
提供了一個名爲center
的計算屬性。Rec
的計算屬性center
提供了自定義的 getter 和 setter 來獲取和設置矩形的中心點,就像它有一個存儲屬性同樣。
2.3 只讀計算屬性
只有 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) print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)") // 輸出 "the volume of fourByFiveByTwo is 40.0" //只讀計算屬性的聲明能夠去掉get關鍵字和花括號
3. 屬性觀察器
屬性觀察器監控和響應屬性值的變化,每次屬性被設置值的時候都會調用屬性觀察器,甚至新的值和如今的值相同的時候也不例外。能夠爲屬性添加以下的一個或所有觀察器:
willSet
在設置新的值以前調用didSet
在新的值被設置以後當即調用看下面一段代碼:
class StepCounter { var totalSteps: Int = 0 { willSet(newTotalSteps) { print("About to set totalSteps to \(newTotalSteps)") } didSet { if totalSteps > oldValue { print("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
4. 類型屬性
實例的屬性屬於一個特定類型實例,每次類型實例化後都擁有本身的一套屬性值,實例之間的屬性相互獨立。也能夠爲類型自己定義屬性,無論類型有多少個實例,這些屬性都只有惟一一份。這種屬性就是類型屬性。值類型的存儲型類型屬性能夠是變量或常量,計算型類型屬性跟實例的計算屬性同樣定義成變量屬性。
4.1 類型屬性語法
使用關鍵字static
來定義值類型的類型屬性,類(class)定義類型屬性。下面的例子演示了存儲型和計算型類型屬性的語法,代碼以下:
struct SomeStructure { static var storedTypeProperty = "Some value." static var computedTypeProperty: Int { // 這裏返回一個 Int 值 } } enum SomeEnumeration { static var storedTypeProperty = "Some value." static var computedTypeProperty: Int { // 這裏返回一個 Int 值 } } class SomeClass {
static var computedTypeProperty: Int { // 這裏返回一個 Int 值 } }
4.2 獲取和設置類型屬性的值
跟實例的屬性同樣,類型屬性的訪問也是經過點運算符來進行,可是,類型屬性是經過類型自己來獲取和設置,而不是經過實例。好比:
print(SomeClass.computedTypeProperty) // 輸出 "42" print(SomeStructure.storedTypeProperty) // 輸出 "Some value." SomeStructure.storedTypeProperty = "Another value." print(SomeStructure.storedTypeProperty) // 輸出 "Another value.」