每一個寫過swift的人都知道可選型的概念。一個可選型表明着它有兩種可能性:它可能有一個值,經過解包這個可選型你能訪問這個值;或者它不是一個值。可使用!來強制解包。可是若是這個可選型爲空的會觸發運行時錯誤。因此若是你不想要運行時錯誤的話,有沒有其餘的選擇能夠優雅的處理爲空的狀況?答案固然是有,一個衆所周知的選擇就是可選型的鏈式調用。swift
在下面的篇幅裏,我會讓你熟悉可選型鏈式調用的多種用法,因此還在等什麼呢?咱們立刻開始吧!數組
在咱們瞭解可選型的鏈式調用的用法以前,讓我先了解一下這是什麼東西。可選型鏈式調用一個查詢和調用當前可能爲nil的可選型的屬性、方法和下標的過程。咱們都知道可選型有兩種可能性。這就是爲何屬性、方法和下標調用可選型時,若是有值就調用成功,若是沒有則返回nil。它被稱爲鏈式調用,由於多個查詢能夠連接在一塊兒,若是此鏈中的任何一個環節爲nil,則整個鏈優雅地失敗。bash
咱們都知道在可選型後面加上!能夠強制解包,相似的在後面加一個問號的話,就表示若是不爲空就訪問屬性、方法或者下標。即便訪問的屬性、方法或者下不是一個可選值,最後返回的結果也是一個可選值。比方說在調用時,一個原本返回String類型的方法會返回String?爲了理解這這二者的區別,咱們來看你個片斷。ui
受限咱們來定義兩個類this
class Student {
var degree: Course?
}
class Course {
var courseTitle = "B.Tech"
}
複製代碼
如今,若是你建立一個Student實例,它的degree屬性會默認初始化爲空,由於它是一個可選型。因此在下面的代碼裏,nidhi有一個degree的屬性,值爲nilspa
let nidhi = Student()
let courseName = nidhi.degree!.courseTitle
// this triggers a runtime error
複製代碼
在這種狀況下,若是你嘗試用!來訪問Student的degree屬性,將會觸發runtime錯誤,由於沒有值去解包。如今咱們來看可選型的鏈式調用ssr
if let courseName = nidhi.degree?.courseTitle {
print("Nidhi is pursuing \(courseName).")
}
else {
print("Unable to retrieve course name.")
}
複製代碼
使用可選型的鏈式調用,若是可選型有值的話,後面的代碼會被執行,若是是nil就斷開,只執行部分代碼。注意儘管course是一個非可選型的String,但因爲它在鏈中被訪問,因此它會返回String?而不是一個String。如今讓咱們將Course實例分配給nidhi.degree,使其再也不包含nil值。code
nidhi.degree = courseTitle() 如今若是你鏈式訪問courseTitle,它會返回包含值 「B.Tech」的String? 因此最後輸出會是「Nidhi is persuing B.Tech.」索引
可選型鏈式調用的一個重要用途是它容許咱們在複雜類中聲明一個可選項,咱們能夠在其中調用任何變量或常量屬性,方法等。這種靈活性使咱們能夠深刻研究相互關聯類型的複雜模型中的子屬性,還能夠檢查咱們是否能夠訪問這些子屬性的屬性,方法和下標。讓咱們經過如下示例更好地理解這一點。在這個例子中,咱們將聲明兩個類,其中一個類是複雜類(College),另外一個類(Student)是訪問其可選值。ip
class Student {
var clg: College?
}
class College {
var classes = [ClassRoom]()
var noOfClasses: Int {
return classes.count
}
subscript (i: Int) -> ClassRoom {
get {
return classes[i]
}
set {
return classes[i] = newValue
}
}
func printNoOfClasses() {
print("Number of Classes: \(noOfClasses)")
}
var address: Address?
}
class ClassRoom {
var className: String
init(className: String) { self.className = className }
}
class Address {
var city: String?
var area: String?
func contactAdd() -> String? {
if city != nil {
return city
} else if area != nil {
return area
} else {
return nil
}
}
}
let john = Student()
if let classCount = john.clg?.noOfClasses {
print("College has a \(classCount) Classes")
}
else {
print("Unable to Retrieve No. of Classes")
}
複製代碼
這裏,類College存儲一組ClassRoom實例,其noOfClasses屬性實現爲計算屬性。計算屬性noOfClasses只返回classes數組中count屬性的值。做爲訪問其classes數組的快捷方式,這個類College提供了一個讀寫下標,能夠在classes數組中的請求索引處提供對類課堂的訪問。 Class College還提供了一種名爲printNoOfClasses的方法,它只是打印了大學課堂的數量。最後,College定義了一個名爲address的可選屬性,其類型爲Address類。用於classes數組的ClassRoom類是一個簡單的類,它有一個名爲className的屬性,以及一個初始化程序,用於將該屬性設置爲合適的類房間名稱。
當咱們在操場上運行上面的代碼時,咱們將獲得一個結果,「沒法檢索數量的類」,由於john.clg爲零。
可選連接可用於訪問可選值的屬性。咱們還經過可選連接瞭解該屬性訪問是否成功。正如咱們在上面的例子中看到的,當咱們嘗試訪問noOfClasses時,連接失敗,由於john.clg是nil。如今讓咱們看看若是咱們嘗試經過如下示例經過可選連接設置屬性值會發生什麼。
let clgAddress = Address()
clgAddress.city = "Bangalore"
clgddress.area = "Shivajinagar"
john.clg?.address = clgAddress
複製代碼
在此示例中,嘗試設置john.clg的address屬性將失敗,由於john.clg當前爲nil。
咱們可使用可選連接在可選值上調用方法,以及檢查該方法調用是否成功。即便該方法沒有返回任何值,這也是可能的。不返回任何值的方法返回void,即返回值()或空元組。若是在可選連接上調用此方法,它將返回void?由於可選連接的結果老是可選的。例如,咱們可使用if語句檢查是否能夠調用printNoOfClasses()方法,即便該方法沒有定義任何返回值。咱們知道經過可選連接調用此方法將成功返回可選值,咱們能夠將printNoOfClasses()調用的返回值與nil進行比較,以瞭解方法調用是否成功。讓咱們看看演示這個的代碼片斷。
if john.clg?.printNoOfClasses() != nil {
print("It was possible to print the number of classes.")
} else {
print("It was not possible to print the number of classes.")
}
// Prints "It was not possible to print the number of classes."
複製代碼
除了調用方法和訪問屬性以外,還可使用可選連接來嘗試從可選值的下標中檢索和設置值,並檢查該下標調用是否成功。這能夠經過如下示例以更好的方式解釋。
if let firstClassName = john.clg?[0].className {
print("The first class name is \(firstClassName).")
} else {
print("Unable to retrieve the first class name.")
}
// Prints "Unable to retrieve the first class name."
複製代碼
john.clg目前爲零,所以下標調用失敗。
即便咱們嘗試經過帶有可選連接的下標來設置新值
john.clg?[0] = Room(name: 「Classroom-1」)
因爲clg目前爲零,所以該下標設置嘗試也會失敗。
若是咱們建立並將實際的College實例分配給john.clg,而且在其classes數組中有一個或多個ClassRoom實例,咱們可使用可選連接來訪問classes數組中的實際項。
若是下標返回一個可選的值,例如,Swift中字典類型的鍵下標,則能夠修改使用可選類型聲明的數組或字典的值。要在其可選的返回值上連接下標,請在下標的右括號後面添加一個問號。要理解這一點,請查看如下代碼段。
關於連接多級可選連接的一個有趣事實是,咱們能夠添加許多級別來深刻查看屬性,方法或下標,可是多級可選連接不會爲返回值添加更多級別的可選性。