Swift11 - 構造過程/可選鏈式調用

基類-不繼承其他類的類
Swift 中的類并不是從一個通用的基類繼承而來的
重寫 - 子類可以為繼承來的實例方法,類方法,實例屬性,類屬性,或下標提供自己定制的實現, 前面加上 override 關鍵字
你可以通過把方法,屬性或下標標記為 final 來防止它們被重寫(final class)來將整個類標記為 final 。這樣的類是不可被繼承的

構造過程

構造過程中常量屬性的賦值
你可以在構造過程中的任意時間點給常量屬性賦值,只要在構造過程結束時它設置成確定的值。一旦常量屬性被賦值,它將永遠不可更改。
指定構造器是類中最主要的構造器。一個指定構造器將初始化類中提供的所有屬性,并調用合適的父類構造器讓構造過程沿著父類鏈繼續往上進行。
類傾向于擁有極少的指定構造器,普遍的是一個類只擁有一個指定構造器
便利構造器是類中比較次要的、輔助型的構造器。

指定構造器
init(parameters) {
    statements
}
便利構造器
convenience init(parameters) {
    statements
}

指定構造器必須調用其直接父類的的指定構造器。
便利構造器必須調用同類中定義的其它構造器。
便利構造器最后必須調用指定構造器。

接下來的例子將在實踐中展示指定構造器、便利構造器以及構造器的自動繼承:

class Food {
    var name: String
    init(name: String) { //指定構造器
        self.name = name
    }
    
    convenience init() { //Food 類同樣提供了一個沒有參數的便利構造器 init()
        self.init(name: "")
    }
}

let namedMeat = Food(name: "Bacon") // namedMeat 的名字是 "Bacon"
let mysteryMeat = Food() // mysteryMeat 的名字是 [Unnamed]


class RecipeIngredient: Food {
    var quantity: Int
    init(name: String, quantity: Int) {
        self.quantity = quantity
        super.init(name: name)
    }
    convenience override init(name: String) { //便利構造器重寫了父類的指定構造器 init(name: String),因此必須在前面使用 override 修飾符
        self.init(name: name, quantity: 1)
    }
}
//所有的這三種構造器都可以用來創建新的 RecipeIngredient 實例:
let oneMysteryItem = RecipeIngredient()
let oneBacon = RecipeIngredient(name: "Bacon")
let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6)

class ShoppingListItem: RecipeIngredient {
    var purchased = false
    var description: String {
        var output = "\(quantity) x \(name)"
        output += purchased ? "?" : "?"
        return output
    }
}

var breakfastList = [
    ShoppingListItem(),
    ShoppingListItem(name: "Bacon"),
    ShoppingListItem(name: "Eggs", quantity: 6)
]
breakfastList[0].name = "Orange juice"
breakfastList[0].purchased = true
for item in breakfastList {
    print(item.description)
}
// 1 x orange juice ?
// 1 x bacon ?
// 6 x eggs ?

可失敗構造器
帶原始值的枚舉類型會自帶一個可失敗構造器 init?(rawValue:),該可失敗構造器有一個合適的原始值類型的 rawValue 形參,選擇找到的相匹配的枚舉成員,找不到則構造失敗。

struct Animal {
    let species: String
    init?(species: String) {
        if species.isEmpty {
            return nil
        }
        self.species = species
    }
}
//枚舉類型的可失敗構造器
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
        }
    }
}
let unknownUnit = TemperatureUnit(symbol: "X") //nil

必要構造器

class SomeClass {
    required init() {
        // 構造器的實現代碼
    }
}

可選鏈式調用

可選鏈式調用是一種可以在當前值可能為 nil 的可選值上請求和調用屬性、方法及下標的方法。
如果可選值有值,那么調用就會成功;如果可選值是 nil,那么調用將返回 nil。
多個調用可以連接在一起形成一個調用鏈,如果其中任何一個節點為 nil,整個調用鏈都會失敗,即返回 nil。

class Person {
    var residence: Residence?
}

class Residence {
    var rooms = [Room]()
    var numberOfRooms: Int {
        return rooms.count
    }
    subscript(i: Int) -> Room {
        get {
            return rooms[i]
        }
        set {
            rooms[i] = newValue
        }
    }
    func printNumberOfRooms() {
        print("The number of rooms is \(numberOfRooms)")
    }
    
    var address: Address?
}

class Address {
    var buildingName: String?
    var buildingNumber: String?
    var street: String?
    func buildingIdentifier() -> String? {
        if buildingName != nil {
            return buildingName
        } else if let buildingNumber = buildingNumber, let street = street {
            return "\(buildingNumber) \(street)"
        } else {
            return nil
        }
    }
}

class Room {
    let name: String
    init(name: String) {
        self.name = name
    }
}

let john = Person()
//可選鏈式調用提供了另一種訪問 numberOfRooms 的方式
if let roomCount = john.residence?.numberOfRooms {
    print("John's residence has \(roomCount) room(s).")
}else {
    print("Unable to retrieve the number of rooms.")
}
// 打印“Unable to retrieve the number of rooms.”
//將一個 Residence 的實例賦給 john.residence,這樣它就不再是 nil 了:
john.residence = Residence()
if let roomCount = john.residence?.numberOfRooms {
    print("John's residence has \(roomCount) room(s).")
}else {
    print("Unable to retrieve the number of rooms.")
}
// 打印“John's residence has 1 room(s).”


let someAddress = Address()
someAddress.buildingNumber = "29"
someAddress.street = "Acacia Road"
john.residence?.address = someAddress
//等號右側的代碼不會被執行。對于上面的代碼來說,很難驗證這一點,因為像這樣賦值一個常量沒有任何副作用

//用一個函數來創建 Address 實例,然后將該實例返回用于賦值。該函數會在返回前打印“Function was called”,這使你能驗證等號右側的代碼是否被執行。
func createAddress() -> Address {
    print("Function was called.")
    
    let someAddress = Address()
    someAddress.buildingNumber = "29"
    someAddress.street = "Acacia Road"

    return someAddress
}
john.residence?.address = createAddress()

//在可選值上通過可選鏈式調用來調用這個方法,該方法的返回類型會是 Void?
if john.residence?.printNumberOfRooms() != nil {
    print("It was possible to print the number of rooms.")
} else {
    print("It was not possible to print the number of rooms.")
}
//同樣的,可以據此判斷通過可選鏈式調用為屬性賦值是否成功。
if (john.residence?.address = someAddress) != nil {
    print("It was possible to set the address.")
}else {
    print("It was not possible to set the address.")
}



//通過可選鏈式調用訪問可選值的下標時,應該將問號放在下標方括號的前面而不是后面
let johnsHouse = Residence()
johnsHouse.rooms.append(Room(name: "Living Room"))
johnsHouse.rooms.append(Room(name: "Kitchen"))
john.residence = johnsHouse
if let firstRoomName = john.residence?[0].name {
    print("The first room name is \(firstRoomName).")
}else {
    print("Unable to retrieve the first room name.")
}
john.residence?[0] = Room(name: "Bathroom")

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