一 、執行個體的初始化
執行個體的初始化是準備一個類、結構或枚舉的執行個體以便使用的過程。初始化包括設定一個執行個體的每一個儲存屬性為一個初始值,以及執行任何其它新的執行個體能夠使用之前需要的設定或初始化。
一個類、結構或枚舉能定義一個初始化方法來設定它的特性,用來確保它的執行個體的所有屬性都有有效初始值。
通過調用類、結構或枚舉提供的初始化方法來執行執行個體的初始化過程。
類的執行個體也能實現一個析構,用來在類的執行個體釋放之前執行任何特定的清除過程來釋放分配的專有資源。
1 、 初始化方法的定義
初始化方法定義與執行個體方法的定義形式類似,可以包含參數,也可以不包含參數。包含參數時也可以為參數指定本地和外部參數名字。但初始化方法的名字固定使用init,且不返回值。
最簡單的初始化方法是不帶參數的init方法。
struct Fahrenheit {
var temperature:Double
init() {
temperature =32.0
}
}
var f =Fahrenheit()
以上定義了一個名字為Fahrenheit的結構,包含一個初始化方法init,用來在該結構執行個體化時為它唯一的儲存屬性temperature分配一個初始值32.0 。
除了在初始化方法中為執行個體的屬性設定初始值外,還能在屬性定義時為其提供一個預設值。
在屬性定義時為其提供預設值是更好的初始化屬性的方法,一方面文法更加簡單,另一方面還可以根據提供的預設值的類型推斷屬性的類型,而且還可以更好的利用預設初始化和初始化繼承的特點。
下面同樣的結構定義,比上面的結構定義文法更簡單。
struct Fahrenheit {
var temperature =32.0
}
你能使用輸入參數和可選的屬性類型來定義一個或多個定製的初始化方法,多個定製的初始化方法根據每個初始化方法提供的參數的名稱和類型加以區分和被調用。
如下例子展示了如何使用參數為一個結構定義不同的初始化方法,以及執行個體化時如何根據初始化方法提供的參數的不同名字來調用相應的初始化方法。
struct Celsius {
var temperatureInCelsius:Double =0.0
init(fromFahrenheitfahrenheit:Double) {
temperatureInCelsius = (fahrenheit -32.0) /1.8
}
init(fromKelvinkelvin:Double) {
temperatureInCelsius =kelvin -273.15
}
}
let boilingPointOfWater =Celsius(fromFahrenheit:212.0)
// boilingPointOfWater.temperatureInCelsius is 100.0
let freezingPointOfWater =Celsius(fromKelvin:273.15)
由於初始化方法的參數名字和類型扮演的重要角色,因此如果你在一個初始化方法的定義中沒有提供一個外部名字,則Swift會自動為它的每一個參數提供一個自動分配的名字,由Swift自動產生的外部參數名字與本地參數名字相同。
與執行個體方法相同,當然如果你不想為初始化方法的參數提供外部參數名字,可以使用’_’作為參數的外部名字。
常量屬性的值能夠在初始化期間被修改,但對於類的執行個體的常量屬性,僅能在引入該屬性的類的初始化方法中修改,而不能被其子類修改。
2、 預設初始化方法
如果一個結構或基類沒有提供定製的初始化方法,且其所有的屬性都提供有預設值,則Swift能夠為其提供一個預設的初始化方法,預設的初始化方法設定新建立的執行個體的所有屬性的值為它們的預設值。如下例子所示:
class ShoppingListItem {
var name:String?
var quantity =1
var purchased =false
}
var item =ShoppingListItem()
由於類ShoppingListItem的所有的三個屬性都提供有預設值,且ShoppingListItem是一個基類,也沒有為其提供定製的初始化方法,因此Swift為其提供了一個預設初始化方法,預設初始化方法不帶參數。
3、 結構類型的成員逐一初始化方法(memberwise Initializers)
如果一個結構的所有的儲存屬性都提供有預設值,且沒有定義任何自己的定製初始化方法,則除了可以使用Swift為其提供的預設初始化方法外,也自動接收一個成員逐一初始化方法。
成員逐一初始化方法是初始化新結構執行個體的成員屬性的一種捷徑,新執行個體的所有屬性的初始值通過名字逐一傳送給該初始化方法然後被設定。如下所示:
struct Size {
var width =0.0,height =0.0
}
let twoByTwo =Size(width:2.0,height:2.0)
在該例子中,結構Size包含僅有的兩個儲存屬性width和height,並都帶有預設值,而其本身也沒有提供初始化方法,因此其自動接收一個為init(width:height:)的成員逐一初始化方法。能夠使用它來初始化一個新的Size執行個體,其屬性的初始值通過成員逐一初始化方法的參數逐一提供。
對於值類型(結構和枚舉),你能在自己定義的初始化方法內部使用self.init調用相同類型的其它初始化方法。
4、 類的初始化
由於類涉及繼承,因此一個類的初始化過程比較複雜,需要在初始化過程完成對類的所有儲存屬性(包括從它的超類鏈繼承的任意屬性)的初始化。Swift為了確保正確完成一個類的初始化,定義了兩類類的初始化方法:指派初始化方法和便利初始化方法。
4.1、 類的指派初始化方法和便利初始化方法
類的指派初始化方法是一個類的主要初始化方法。一個類的指派初始化方法初始化該類本身引入的所有的屬性,然後向上調用其直接超類的初始化方法來繼續超類璉的初始化過程。一個類必須有至少一個指派初始化方法,通常一個類僅有一個指派初始化方法。
類的便利初始化方法是類的次要初始化方法,你能為類定義一個便利初始化方法來調用相同類的其它初始化方法。一個類可以不必提供便利初始化方法。
便利初始化方法作為一種便利的初始化方法,主要用來方便建立某些特定的執行個體或者特定輸入值類型的類的執行個體,因此在便利初始化方法中調用指派初始化方法時,對於指派初始化方法的一些參數被設定為預設值。
類的指派初始化方法和便利初始化方法之間的調用必須遵守如下規則:
1)指派初始化方法必須調用它的直接超類的指派初始化方法;
2)便利初始化方法必須調用相同類的另外的可以使用的初始化方法;
3) 便利初始化方法最後必須調用一個指派初始化方法。
類的指派初始化方法文法與值類型的簡單初始化方法相同:
init(parameters) {
statements
}
便利初始化方法的文法除了使用convenience關鍵字來標示外,文法與指派初始化方法相同。
convenience init(parameters) {
statements
}
4.2、 類的兩階段初始化
在Swift中類的初始化分成兩個階段完成,在第一個階段,每一個儲存屬性被引入它的類的初始化方法分配一個初始值。一旦每個儲存屬性的初始狀態確定,開始第二個初始化階段:在新的執行個體能夠使用之前,進一步定製它的儲存屬性。
為了正確完成一個類的兩階段初始化過程,Swift進行如下安全檢查:
1) 指派初始化方法必須在調用它的直接超類的初始化方法之前確保由它的類引入的所有的屬性被初始化。
2) 指派初始化方法在為一個繼承的屬性分配一個值之前必須向上調用它的直接超類的初始化方法;
3) 便利初始化方法必須在為任何屬性分配值之前調用其它的初始化方法;
4) 一個初始化方法在第一個階段完成前不能調用其它任何執行個體方法,讀任何執行個體屬性的值或者引用self,這是因為這時執行個體還處於記憶體不確定狀態。
4.3、 初始化方法的繼承和重寫
與Objective-C語言不同,Swift 中子類預設不繼承它的超類的初始化方法。但允許在子類中重寫超類的初始化方法。與方法、屬性、下標不同,初始化方法的重寫不需要寫一個override標識。
4.4、 自動初始化繼承
在一些條件下,超類的初始化方法也能被它的子類自動繼承。
規則1:如果一個子類沒有定義任何指派初始化方法,則自動繼承它的超類的所有指派初始化方法。即對於指派初始化方法繼承而言,沒有則繼承。
規則2:如果一個子類提供了其超類的所有指派初始化方法的實現,可以是通過規則1繼承來的,也可以是提供自己特定的實現,那麼它自動繼承其超類的所有便利初始化方法。即對於便利初始化方法繼承而言如果已實現超類的所有指派初始化方法,則自動繼承所有便利初始化方法。
5、 使用閉合或功能為屬性設定預設值。
你能使用一個閉合或全域功能來為一個儲存屬性提供特定的預設值。在該屬性所屬類型的新的執行個體被初始化時,為一個屬性提供預設值的閉合或全域功能被調用,且返回一個值作為該屬性的預設值。如下所示:
class SomeClass {
let someProperty:SomeType = {
return someValue
}()
}
該例使用一個閉合為someProperty屬性提供預設值,該閉合以一個圓括弧結束,說明該閉合能夠被執行。
需要注意:在使用一個閉合為一個屬性分配預設值時,因為在閉合執行時,該執行個體還沒有初始化完成,因此在閉合內部不能存取執行個體的其它任何屬性值,即使那些屬性帶有預設值,也不能使用隱含的self屬性,也不能調用任何執行個體的方法。
二、析構
在一個執行個體不再需要時,Swift會自動釋放它。Swift使用automatic reference counting (ARC)來實現一個執行個體的記憶體管理。因此當執行個體釋放時,使用者不需要手工清除它所使用的系統資源。可是當你的執行個體包含和使用了自己分配的資源時,你可能需要執行一些額外的清除工作。例如建立一個開啟一個檔案的類,就可能需要在類的執行個體釋放前關閉該檔案。
每個類能夠定義至少一個析構,析構文法如下:
deinit {
// perform the deinitialization
}
一個執行個體的析構在執行個體釋放之前自動被調用。超類的析構被子類繼承,超類的析構能夠在子類的析構實現的最後被自動調用。
超類的析構總是被調用,即使一個沒有提供自己的析構的子類。
在一個執行個體的析構完成之前該執行個體還沒有被釋放,因此在析構內部能夠存取執行個體的所有屬性。
著作權,轉載時請清楚註明連結和出處,謝謝!