標籤:使用 strong 資料 io for re
屬性和常量
如果建立了一個結構體的執行個體並賦值給一個常量,則無法修改執行個體的任何屬性:
let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)rangeOfFourItems.firstValue = 6
- 當實值型別的執行個體被聲明為常量的時候,它的所有屬性也就成了常量
- 當參考型別的執行個體賦給一個常量後,仍然可以修改執行個體的變數屬性。
延遲屬性
- 屬性聲明前使用@lazy來標示一個延遲儲存屬性。
- 延遲儲存屬性是指當第一次被調用的時候才會計算其初始值的屬性
- 必須將延遲儲存屬性聲明成變數(使用var關鍵字),因為屬性的值在執行個體構造完成之前可能無法得到。而常量屬性在構造過程完成之前必須要有初始值,因此無法聲明成延遲屬性。
-
什麼時候使用延遲屬性?
-
當屬性的值依賴於在執行個體的構造過程結束前無法知道具體值的外部因素時
-
當屬性的值需要複雜或大量計算時,可以只在需要的時候來計算它
class DataManager { @lazy var importer = DataImporter() var data = String[]() // 這是提供資料管理功能}
計算屬性:getter和setter
如果計算屬性的 setter 沒有定義表示新值的參數名,則可以使用預設名稱newValue。
必須使用var關鍵字定義計算屬性,包括唯讀計算屬性,因為它們的值不是固定的。let關鍵字只用來聲明常量屬性,表示初始化後再也無法修改的值。
struct Rect{ var _center:String; var center: String { get { return _center; } set (newCenter){ _center = newCenter } }}//使用newValuestruct Rect2{ var _center:String; var center: String { get { return _center; } set{ _center = newValue } }}
屬性觀察器
- 屬性觀察器監控和響應屬性值的變化,每次屬性被設定值的時候都會調用屬性觀察器,甚至新的值和現在的值相同的時候也不例外。
- 可以為除了延遲儲存屬性之外的其他儲存屬性添加屬性觀察器,
- 不需要為無法重載的計算屬性添加屬性觀察器,因為可以通過 setter 直接監控和響應值的變化。
- 可以通過重載屬性的方式為繼承的屬性(包括儲存屬性和計算屬性)添加屬性觀察器
屬性觀察器:
willSet
在設定新的值之前調用,willSet觀察器會將新的屬性值作為固定參數傳入,在willSet的實現代碼中可以為這個參數指定一個名稱,如果不指定則參數仍然可用,這時使用預設名稱newValue表示。
didSet
在新的值被設定之後立即調用,didSet觀察器會將舊的屬性值作為參數傳入,可以為該參數命名或者使用預設參數名oldValue。
- willSet和didSet觀察器在屬性初始化過程中不會被調用,它們只會當屬性的值在初始化之外的地方被設定時被調用。
struct Test{ var test:Int = 0{ willSet { println(newValue) } didSet{ println(oldValue) } }}var a = Test();a.test = 5;
全域變數,局部變數和延遲屬性,計算屬性,屬性觀察器
全域或局部變數都屬於儲存型變數,跟儲存屬性類似,它提供特定類型的儲存空間,並允許讀取和寫入。
- 在全域或局部範圍都可以定義計算型變數和為儲存型變數定義觀察器,計算型變數跟計算屬性一樣,返回一個計算的值而不是儲存值,聲明格式也完全一樣。
- 全域的常量或變數都是延遲計算的,跟延遲儲存屬性相似,不同的地方在於,全域的常量或變數不需要標記@lazy特性。 局部範圍的常量或變數不會延遲計算。
var test:Int = 0{willSet { println(newValue)}didSet{ println(oldValue)}}test = 5 ;var str:String{get{ return String(test);}set {test = newValue.toInt()!+5}}println(str);str = "4";println(str)
類型屬性---靜態屬性
使用關鍵字static來定義實值型別的類型屬性,關鍵字class來為類(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 { class var computedTypeProperty: Int { // 這裡返回一個 Int 值 }}
類型屬性是通過類型本身來擷取和設定,而不是通過執行個體。
println(SomeClass.computedTypeProperty)// 輸出 "42"println(SomeStructure.storedTypeProperty)// 輸出 "Some value."SomeStructure.storedTypeProperty = "Another value."println(SomeStructure.storedTypeProperty)// 輸出 "Another value.”
self 和 parent
- 類型的每一個執行個體都有一個隱含屬性叫做self,self完全等同於該執行個體本身
- 你不必在你的代碼裡面經常寫self。不論何時,只要在一個方法中使用一個已知的屬性或者方法名稱,如果你沒有明確的寫self,Swift 假定你是指當前執行個體的屬性或者方法
- 使用這條規則的主要情境是執行個體方法的某個參數名稱與執行個體的某個屬性名稱相同的時候。在這種情況下,參數名稱享有優先權,並且在引用屬性時必須使用一種更嚴格的方式。這時你可以使用self屬性來區分參數名稱和屬性名稱。
- 變異方法能夠賦給隱含屬性self一個全新的執行個體。
- 在類型方法的方法體(body)中,self指向這個類型本身,而不是類型的某個執行個體。對於結構體和枚舉來說,這意味著你可以用self來消除靜態屬性和靜態方法參數之間的歧義
struct Point { var x = 0.0, y = 0.0 mutating func moveByX(deltaX: Double, y deltaY: Double) { self = Point(x: x + deltaX, y: y + deltaY) }}enum TriStateSwitch { case Off, Low, High mutating func next() { switch self { case Off: self = Low case Low: self = High case High: self = Off } }}var ovenLight = TriStateSwitch.LowovenLight.next()// ovenLight 現在等於 .HighovenLight.next()// ovenLight 現在等於 .Off
變異 mutating
- 結構體和枚舉是實值型別。一般情況下,實值型別的屬性不能在它的執行個體方法中被修改。
- 要使用變異方法, 將關鍵字mutating 放到方法的func關鍵字之前
- 不能在結構體類型常量上調用變異方法,因為常量的屬性不能被改變,即使想改變的是常量的變數屬性也不行
struct Point { var x = 0.0, y = 0.0 mutating func moveByX(deltaX: Double, y deltaY: Double) { x += deltaX y += deltaY }}var somePoint = Point(x: 1.0, y: 1.0)somePoint.moveByX(2.0, y: 3.0)
執行個體方法
- 執行個體方法能夠隱式訪問它所屬類型的所有的其他執行個體方法和屬性。
- 執行個體方法只能被它所屬的類的某個特定執行個體調用。
- 執行個體方法不能脫離於現存的執行個體而被調用。
Swift 中方法的名稱通常用一個介詞指向方法的第一個參數,比如:with,for,by等等。
關於方法的外部參數:
- Swift 預設僅給方法的第一個參數名稱一個局部參數名稱;預設同時給第二個和後續的參數名稱局部參數名稱和外部參數名稱。
- 可以自己添加一個顯式的外部名稱或者用一個井號(#)作為第一個參數的首碼來把這個局部名稱當作外部名稱使用。
- 如果你不想為方法的第二個及後續的參數提供一個外部名稱,可以通過使用底線(_)作為該參數的顯式外部名稱,這樣做將覆蓋預設行為。
class Counter { var count: Int = 0 func incrementBy(amount: Int, numberOfTimes: Int) { count += amount * numberOfTimes }}let counter = Counter()counter.incrementBy(5, numberOfTimes: 3)
類型方法--靜態方法
聲明類的類型方法,在方法的func關鍵字之前加上關鍵字class;聲明結構體和枚舉的類型方法,在方法的func關鍵字之前加上關鍵字static。
struct LevelTracker { static var highestUnlockedLevel = 1 static func unlockLevel(level: Int) { if level > highestUnlockedLevel { highestUnlockedLevel = level } } static func levelIsUnlocked(level: Int) -> Bool { return level <= highestUnlockedLevel } var currentLevel = 1 mutating func advanceToLevel(level: Int) -> Bool { if LevelTracker.levelIsUnlocked(level) { currentLevel = level return true } else { return false } }}