構造過程是使用類、結構體或枚舉類型的實例之前的準備過程。在新實例可用前必須執行這個過程,具體操作包括設置實例中每個存儲型屬性的初始值和執行其他必須的設置或初始化工作。
通過定義構造器來實現構造過程,這些構造器可以看做是用來創建特定類型新實例的特殊方法。與oc中的構造器不同,swift的構造器無需返回值,它們的主要任務是保證新實例在第一次使用前完成正確的初始化。
類的實例也可以通過定義析構器在實例釋放之前執行特定的清除工作。
存儲屬性的初始賦值
構造器
struct Fahrenheit {
var temperature:Double
init() {
temperature = 32.0
}
}
var f = Fahrenheit()
print("\(f.temperature)")
默認屬性值
struct Fahrenheit {
var temperature:Double = 32.0
}
自定義構造過程
構造參數
struct Celsius {
var temperatureInCelsius:Double
init(fromFahrenheit fahrenheit:Double) {
temperatureInCelsius = (fahrenheit - 32.0) / 1.8
}
init(fromKelvin kelvin:Double) {
temperatureInCelsius = kelvin - 273.15
}
}
let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
let freezingPointOfWater = Celsius(fromKelvin:2713.15)
參數的內部名稱和外部名稱
struct Color {
let red,green,blue:Double
init(red:Double,green:Double,blue:Double) {
self.red = red
self.green = green
self.blue = blue
}
init(white:Double) {
red = white
green = white
blue = white
}
}
let magenta = Color(red:1.0,green:0.0,blue:1.0)
let halfGray = Color(white:0.5)
如果不通過外部參數名字傳值,沒有辦法調用這個構造器。只要構造器定義了某個外部參數名,必須使用它。不帶外部名的構造器參數
可選屬性類型
class SurveyQuestion {
var text:String
var response:String?
init(text:String) {
self.text = text
}
func ask() {
print(text)
}
}
調查問題的答案在回答前是無法確定的,因此我們將屬性response聲明爲String?類型,或者說是可選字符串類型。當SurveyQuestion實例化時,將自動賦值爲nil,表明此字符串暫時還沒有值。構造過程中常量屬性的修改
默認構造器
class ShoppingListItem {
var name:String?
var quantity = 1
var purchased = false
}
由於ShoppingListItem類中的所有屬性都有默認值,它是沒有父類的基類,將自動獲取一個可以爲所有屬性設置默認值的默認構造器。類的繼承和構造過程
指定構造器和便利構造器
指定構造器和便利構造器的語法
init(<#parameters#>) {
<#statements#>
}
便利構造器: convenience init(<#parameters#>) {
<#statements#>
}
類的構造器代理規則
構造器的繼承和重寫
class Vehicle{
var numberOfWheels = 0
var description:String {
return "\(numberOfWheels)"
}
}
class Bicycle: Vehicle {
override init(){
super.init()
numberOfWheels = 2
}
}
子類Bicycle定義了一個自定義指定構造器。這個指定的構造器和父類的指定構造器相匹配,所以帶有override。構造器的自動繼承
指定構造器和便利構造器實踐
class Food {
var name:String
init(name:String) {
self.name = name
}
convenience init(){
self.init(name:"[Unnamed]")
}
class RecipeIngredient: Food {
var quantity:Int
init(name:String,quantity:Int) {
self.quantity = quantity
super.init(name: name)
}
override convenience init(name:String){
self.init(name:name,quantity:1)
}
}
class ShoppingListItem: RecipeIngredient {
var purchased = false
var description:String {
var output = "\(quantity) x \(name)"
output += purchased ? " ?" : " ?"
return output
}
}
由於它爲自己引入的所有屬性都提供了默認值,並自己沒有定義任何構造器,將自動繼承所有父類中的指定構造器和便利構造器。可失敗構造器
struct Animal {
let species:String
init?(species:String) {
if species.isEmpty {
return nil
}
self.species = species
}
}
可以通過該可失敗的構造器來構建一個Animal的實例,並檢查構造過程是否成功: let someCreature = Animal(species:"Giraffe")
if let giraffe = someCreature {
print("\(giraffe.species)")
}
如果在這裏傳入的是空字符串就會導致構造失敗,返回的就是nil。枚舉類型的可失敗構造器
enum TemperatureUnit {
case Kelvin,Celsius,Fahrenheit
init?(symbol:Character) {
switch symbol {
case "K":
self = .Kelvin
case "C":
self = .Celsius
case "F":
self = .Fahrenheit
default:
return nil
}
}
}
可以利用該可失敗構造器在三個枚舉成員中獲取一個相匹配的枚舉成員,當參數的值不能與任何成員相匹配,則構造失敗。帶原始值的枚舉類型的可失敗構造器
enum TemperatureUnit:Character {
case Kelvin = "K",Celsius = "C",Fahrenheit = "F"
}
構造失敗的傳遞
class Product {
let name:String
init?(name:String) {
if name.isEmpty {
return nil
}
self.name = name
}
}
class CartItem: Product {
let quantity:Int
init?(name:String,quantity:Int) {
if quantity < 1 {
return nil
}
self.quantity = quantity
super.init(name: name)
}
}
CartItem可失敗構造器首先驗證接受的quantity值是否大於等於1,如果quantity值無效,則立即終止整個構造過程,返回失敗結果,且不再執行餘下代碼,同樣,Product的可失敗構造器首先檢查name值,假如name值爲空字符串,則構造器立即執行失敗。重寫一個可失敗構造器
class Document {
var name:String?
init() {
}
init?(name:String) {
self.name = name
if name.isEmpty {
return nil
}
}
}
下面的子類重寫了父類的兩個指定構造器,確保了無論是使用init()構造器,還是init(name:)構造器併爲參數傳遞空字符串,生成的實例中的name屬性總有初始值“[Untitled]”: class AutomaticallyNameDocument: Document {
override init(){
super.init()
self.name = "[Untitled]"
}
override init(name:String){
super.init()
if name.isEmpty {
self.name = "[Untitled]"
}else{
self.name = name
}
}
}
子類用一個可失敗構造器重寫了父類的可失敗構造器。因爲子類用另一種方式處理了空字符串的情況,所以不再需要一個可失敗的構造器,因此子類用一個非可失敗的構造器代替了父類的可失敗的構造器。