類
基類-不繼承其他類的類
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\".")
}
}