如果乙個類,結構體或列舉型別的物件,在構造自身的過程中有可能失敗,則為其定義乙個可失敗構造器,是非常有必要的。這裡所指的「失敗」是指,
如給構造器傳入無效的引數值,或缺少某種所需的外部資源,又或是不滿足某種必要的條件等。
為了妥善處理這種構造過程中可能會失敗的情況。你可以在乙個類,結構體或是列舉型別的定義中,新增乙個或多個可失敗構造器。其語法為在init
關鍵字後面加添問號(init?)
。
可失敗構造器,在構建物件的過程中,建立乙個其自身型別為可選型別的物件。你通過return nil
語句,來表明可失敗構造器在何種情況下「失敗」。
struct animalself.species = species
}}// 生成someanimal這個例項,需要注意的是這個例項的型別是可選型別(animal?)
let someanimal = animal(species: "giraffe")
if let giraffe = someanimal
// 生成乙個構造過程會失敗的例項
let anonymouscreature = animal(species: "")
if anonymouscreature == nil
你可以通過構造乙個帶乙個或多個引數的可失敗構造器來獲取列舉型別中特定的列舉成員。還能在引數不滿足你所期望的條件時,導致構造失敗。
enum temperatureunit}}let kelvinunit = temperatureunit(symbol: "k") // kelvin
let unknowunit = temperatureunit(symbol: "x") // nil
帶原始值的列舉型別會自帶乙個可失敗構造器init?(rawvalue:)
,該可失敗構造器有乙個名為rawvalue
的預設引數,其型別和列舉型別的原始值型別一致,如果該引數的值能夠和列舉型別成員所帶的原始值匹配,則該構造器構造乙個帶此原始值的列舉成員,否則構造失敗。
enum temperatureunit: characterlet kelvinunit = temperatureunit(rawvalue: "k") // kelvin
let unknowunit = temperatureunit(rawvalue: "x") // nil
值型別(如結構體或列舉型別)的可失敗構造器,對何時何地觸發構造失敗這個行為沒有任何的限制。比如在前面的例子中,結構體animal
的可失敗構造器觸發失敗的行為,甚至發生在species
屬性的值被初始化以前。而對類而言,就沒有那麼幸運了。類的可失敗構造器只能在所有的類屬性被初始化後和所有類之間的構造器之間的**呼叫發生完後觸發失敗行為。
class product}}
可失敗構造器同樣滿足在構造器鏈中所描述的構造規則。其允許在同一類,結構體和列舉中橫向**其他的可失敗構造器。類似的,子類的可失敗構造器也能向上**基類的可失敗構造器。
無論是向上**還是橫向**,如果你**的可失敗構造器,在構造過程中觸發了構造失敗的行為,整個構造過程都將被立即終止,接下來任何的構造**都將不會被執行。
可失敗構造器也可以**呼叫其它的非可失敗構造器。通過這個方法,你可以為已有的構造過程加入構造失敗的條件。
class product}}class cartitem: product
}}if let item = cartitem(name: "shirt", quantity: 0) else
就如同其它構造器一樣,你也可以用子類的可失敗構造器重寫基類的可失敗構造器。或者你也可以用子類的非可失敗構造器重寫乙個基類的可失敗構造器。這樣做的好處是,即使基類的構造器為可失敗構造器,但當子類的構造器在構造過程不可能失敗時,我們也可以把它修改過來。
注意當你用乙個子類的非可失敗構造器重寫了乙個父類的可失敗構造器時,子類的構造器將不再能向上**父類的可失敗構造器。乙個非可失敗的構造器永遠也不能**呼叫乙個可失敗構造器。
注意: 你可以用乙個非可失敗構造器重寫乙個可失敗構造器,但反過來卻行不通。
class document// 相反 這個構造器構建了name不為空的例項
init?(name: string)
self.name = name
}}class automaticallynameddocument: document
// 將父類的可失敗構造器重寫為普通自定義構造器,保證了name屬性永遠有值
override init(name: string) else
}}
通常來說我們通過在init
關鍵字後新增問號的方式來定義乙個可失敗構造器,但你也可以使用通過在init
後面新增驚嘆號的方式來定義乙個可失敗構造器(init!)
,該可失敗構造器將會構建乙個特定型別的隱式解析可選型別的物件。
你可以在init?
構造器中**呼叫init!
構造器,反之亦然。 你也可以用init?
重寫init!
,反之亦然。 你還可以用init
**呼叫init!
,但這會觸發乙個斷言:是否init!
構造器會觸發構造失敗?
在類的構造器前新增required
修飾符表明所有該類的子類都必須實現該構造器
注意: 如果子類繼承的構造器能滿足必要構造器的需求,則你無需顯示的在子類中提供必要構造器的實現。
class someclass}class subclass: someclass
}
如果某個儲存型屬性的預設值需要特別的定製或準備,你就可以使用閉包或全域性函式來為其屬性提供定製的預設值。每當某個屬性所屬的新型別例項建立時,對應的閉包或函式會被呼叫,而它們的返回值會當做預設值賦值給這個屬性。
這種型別的閉包或函式一般會建立乙個跟屬性型別相同的臨時變數,然後修改它的值以滿足預期的初始狀態,最後將這個臨時變數的值作為屬性的預設值進行返回。
class someclass ()// 注意閉包結尾的大括號後面接了一對空的小括號。這是用來告訴 swift 需要立刻執行此閉包。如果你忽略了這對括號,相當於是將閉包本身作為值賦值給了屬性,而不是將閉包的返回值賦值給屬性。
}
Swift 對比學習Swift構造器
首先建立乙個類 實現方法如下 而當我們利用建構函式生成例項時有以下幾種方法 在oc的例子中,構造器initwithname age 內部呼叫了另乙個構造器,避免了 重複,下面來圍觀swift中如何實現。在swift中,當你建立乙個類或者結構體的時候,它們的屬性一定有初值 否則編譯不過,例如let a...
學習Swift 構造器(上)
構造過程是為了使用某個類 結構體或列舉型別的例項而進行的準備過程。這個過程包含了為例項中的每個儲存型屬性設定初始值和為其執行必要的準備和初始化任務。構造過程是通過定義構造器 initializers 來實現的,這些構造器可以看做是用來建立特定型別例項的特殊方法。與 objective c 中的構造器...
Swift之構造器(上)
目錄 swift之構造器 上 swift之構造器 中 swift之構造器 下 swift賦予自定義型別更加豐富的功能,乙個顯著地方就是構造過程。swift可以為自定義型別設定構造器來初始化乙個例項。有關swift構造器的使用特點可以總結如下 1.構造器適用於類 結構體 列舉。是新的例項可用之前必須執...