Swift-構造過程

最近項目使用的是OC,后頭看之前用Swift開發的一個項目時,發現很多細節都忘記了????。
為了回憶和以后方便查看,現在根據官方文檔swift編程語言,做下筆記。

構造過程是使用類、結構體或枚舉類型的實例之前的準備過程。在新實例可用前必須執行這個過程,具體操作包括設置實例中每個存儲型屬性的初始值和執行其他必須的設置或初始化工作。

與 Objective-C 中的構造器不同,Swift 的構造器無需返回值,它們的主要任務是保證新實例在第一次使用前完成正確的初始化。

1、存儲屬性的初始賦值

類和結構體在創建實例時,必須為所有存儲型屬性設置合適的初始值。存儲型屬性的值不能處于一個未知的狀態。

當你為存儲型屬性設置默認值或者在構造器中為其賦值時,它們的值是被直接設置的,不會觸發任何屬性觀察者。

  • 構造器

構造器在創建某個特定類型的新實例時被調用。它的最簡形式類似于一個不帶任何參數的實例方法,以關鍵字init命名

init() {
    // 在此處執行構造過程
}

例如:定義了一個用來保存華氏溫度的結構體Fahrenheit,它擁有一個Double類型的存儲型屬性temperature

這個結構體定義了一個不帶參數的構造器init,并在里面將存儲型屬性temperature的值初始化為32.0。

struct Fahrenheit {
    var temperature: Double
    init() {
        temperature = 32.0
    }
}
var f = Fahrenheit()
print("The default temperature is \(f.temperature)° Fahrenheit")
// 打印 "The default temperature is 32.0° Fahrenheit"
  • 自定義構造過程

你可以通過輸入參數和可選類型的屬性來自定義構造過程,也可以在構造過程中修改常量屬性。

構造參數

自定義構造過程時,可以在定義中提供構造參數,指定所需值的類型和名字。構造參數的語法和函數的參數相同。

例如:下面例子中定義了一個包含攝氏度溫度的結構體Celsius

構造器擁有一個構造參數,其外部名字為fromFahrenheit,內部名字為fahrenheit

struct Celsius {
    var temperatureInCelsius: Double
    init(fromFahrenheit fahrenheit: Double) {
        temperatureInCelsius = (fahrenheit - 32.0) / 1.8
    }
}
let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
// boilingPointOfWater.temperatureInCelsius 是 100.0
  • 默認構造器

如果結構體或類的所有屬性都有默認值,同時沒有自定義的構造器,那么 Swift 會給這些結構體或類提供一個默認構造器(default initializers)。這個默認構造器將簡單地創建一個所有屬性值都設置為默認值的實例。

例如:創建了一個類ShoppingListItem,它封裝了購物清單中的某一物品的屬性:名字(name)、數量(quantity)和購買狀態 purchase state

由于ShoppingListItem類中的所有屬性都有默認值,且它是沒有父類的基類,它將自動獲得一個可以為所有屬性設置默認值的默認構造器

class ShoppingListItem {
    var name: String?
    var quantity = 1
    var purchased = false
}
var item = ShoppingListItem()
結構體的逐一成員構造器

如果結構體沒有提供自定義的構造器,它們將自動獲得一個逐一成員構造器,即使結構體的存儲型屬性沒有默認值。

例如:

struct Size {
    var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0)
如果你為某個值類型定義了一個自定義的構造器,你將無法訪問到默認構造器(如果是結構體,還將無法訪問逐一成員構造器)。

假如你希望默認構造器、逐一成員構造器以及你自己的自定義構造器都能用來創建實例,可以將自定義的構造器寫到擴展(extension)中,而不是寫在值類型的原始定義中。

  • 類的繼承和構造過程

類里面的所有存儲型屬性——包括所有繼承自父類的屬性——都必須在構造過程中設置初始值。
Swift 為類類型提供了兩種構造器來確保實例中所有存儲型屬性都能獲得初始值,它們分別是指定構造器和便利構造器。

指定構造器是類中最主要的構造器。一個指定構造器將初始化類中提供的所有屬性,并根據父類鏈往上調用父類的構造器來實現父類的初始化。
每一個類都必須擁有至少一個指定構造器。在某些情況下,許多類通過繼承了父類中的指定構造器而滿足了這個條件。

便利構造器是類中比較次要的、輔助型的構造器。你可以定義便利構造器來調用同一個類中的指定構造器,并為其參數提供默認值。

1、指定構造器和便利構造器的語法

類的指定構造器寫法跟值類型簡單構造器一樣

init(parameters) {
    statements
}

便利構造器也采用相同樣式的寫法,但需要在init關鍵字之前放置convenience關鍵字,并使用空格將它們倆分開

convenience init(parameters) {
    statements
}
2、類的構造器代理規則

為了簡化指定構造器和便利構造器之間的調用關系,Swift 采用以下三條規則來限制構造器之間的代理調用:

規則 1:指定構造器必須調用其直接父類的的指定構造器。
規則 2:便利構造器必須調用同類中定義的其它構造器。
規則 3:便利構造器必須最終導致一個指定構造器被調用。

如下圖:

3、兩段式構造過程

Swift 中類的構造過程包含兩個階段。第一個階段,每個存儲型屬性被引入它們的類指定一個初始值。當每個存儲型屬性的初始值被確定后,第二階段開始,它給每個類一次機會,在新實例準備使用之前進一步定制它們的存儲型屬性。

Swift 編譯器將執行 4 種有效的安全檢查,以確保兩段式構造過程能不出錯地完成

安全檢查 1:
指定構造器必須保證它所在類引入的所有屬性都必須先初始化完成,之后才能將其它構造任務向上代理給父類中的構造器。
安全檢查 2:
指定構造器必須先向上代理調用父類構造器,然后再為繼承的屬性設置新值。如果沒這么做,指定構造器賦予的新值將被父類中的構造器所覆蓋。
安全檢查 3:
便利構造器必須先代理調用同一類中的其它構造器,然后再為任意屬性賦新值。如果沒這么做,便利構造器賦予的新值將被同一類中其它指定構造器所覆蓋。
安全檢查 4:
構造器在第一階段構造完成之前,不能調用任何實例方法,不能讀取任何實例屬性的值,不能引用self作為一個值。

4、構造器的繼承和重寫

當你重寫一個父類的指定構造器時,你總是需要寫override修飾符,即使你的子類將父類的指定構造器重寫為了便利構造器。
如果你編寫了一個和父類便利構造器相匹配的子類構造器,不需要加override前綴。

class Vehicle {
    var numberOfWheels = 0
    var description: String {
        return "\(numberOfWheels) wheel(s)"
    }
}

Vehicle類只為存儲型屬性提供默認值,而不自定義構造器。因此,它會自動獲得一個默認構造器.

let vehicle = Vehicle()
print("Vehicle: \(vehicle.description)")
// Vehicle: 0 wheel(s)

下面例子中定義了一個Vehicle的子類Bicycle

class Bicycle: Vehicle {
    override init() {
        super.init()
        numberOfWheels = 2
    }
}

子類Bicycle定義了一個自定義指定構造器init()。這個指定構造器和父類的指定構造器相匹配,所以Bicycle中的指定構造器需要帶上override修飾符。
Bicycle的構造器init()以調用super.init()方法開始,這個方法的作用是調用Bicycle的父類Vehicle的默認構造器。這樣可以確保Bicycle在修改屬性之前,它所繼承的屬性numberOfWheels能被Vehicle類初始化。在調用super.init()之后,屬性numberOfWheels的原值被新值2替換。

5、構造器的自動繼承

子類在默認情況下不會繼承父類的構造器。但是如果滿足特定條件,父類構造器是可以被自動繼承的。在實踐中,這意味著對于許多常見場景你不必重寫父類的構造器,并且可以在安全的情況下以最小的代價繼承父類的構造器。

假設你為子類中引入的所有新屬性都提供了默認值,以下 2 個規則適用:
規則 1
如果子類沒有定義任何指定構造器,它將自動繼承所有父類的指定構造器。
規則 2
如果子類提供了所有父類指定構造器的實現——無論是通過規則 1 繼承過來的,還是提供了自定義實現——它將自動繼承所有父類的便利構造器。

  • 可失敗構造器

如果一個類、結構體或枚舉類型的對象,在構造過程中有可能失敗,則為其定義一個可失敗構造器。這里所指的“失敗”是指,如給構造器傳入無效的參數值,或缺少某種所需的外部資源,又或是不滿足某種必要的條件等。

為了妥善處理這種構造過程中可能會失敗的情況。你可以在一個類,結構體或是枚舉類型的定義中,添加一個或多個可失敗構造器。其語法為在init關鍵字后面添加問號(init?)。

可失敗構造器會創建一個類型為自身類型的可選類型的對象。你通過return nil語句來表明可失敗構造器在何種情況下應該“失敗”。
嚴格來說,構造器都不支持返回值。因為構造器本身的作用,只是為了確保對象能被正確構造。因此你只是用return nil表明可失敗構造器構造失敗,而不要用關鍵字return來表明構造成功。

struct Animal {
    let species: String
    init?(species: String) {
        if species.isEmpty { return nil }
        self.species = species
    }
}

let someCreature = Animal(species: "Giraffe")
// someCreature 的類型是 Animal? 而不是 Animal

if let giraffe = someCreature {
    print("An animal was initialized with a species of \(giraffe.species)")
}
// 打印 "An animal was initialized with a species of Giraffe"
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,702評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,615評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,606評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,044評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,826評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,227評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,307評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,447評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,992評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,807評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,001評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,550評論 5 361
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,243評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,667評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,930評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,709評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,996評論 2 374

推薦閱讀更多精彩內容

  • 構造過程是使用類、結構體或枚舉類型的實例之前的準備過程。在新實例可用前必須執行這個過程,具體操作包括設置實例中每個...
    CDLOG閱讀 347評論 0 1
  • 中文文檔 一、存儲屬性的初始賦值 類和結構體在創建實例時,必須為所有存儲型屬性設置合適的初始值。存儲型屬性的值不能...
    伯wen閱讀 195評論 0 1
  • 這是16年5月份編輯的一份比較雜亂適合自己觀看的學習記錄文檔,今天18年5月份再次想寫文章,發現簡書還為我保存起的...
    Jenaral閱讀 2,808評論 2 9
  • ?構造過程是使用類、結構體或枚舉類型一個實例的準備過程。在新實例可用前必須執行這個過程,具體操作包括設置實例中每個...
    EndEvent閱讀 642評論 0 3
  • 本章將會介紹 存儲屬性的初始賦值自定義構造過程默認構造器值類型的構造器代理類的繼承和構造過程可失敗構造器必要構造器...
    寒橋閱讀 776評論 0 0