Swift4 基礎部分: Optional Chaining(可選鏈)

本文是學習《The Swift Programming Language》整理的相關隨筆,基本的語法不作介紹,主要介紹Swift中的一些特性或者與OC差異點。

系列文章:

可選鏈可替代強制解析(Optional Chaining as an Alternative to Forced Unwrapping)

You specify optional chaining by placing a question mark 
(?) after the optional value on which you wish to call a 
property, method or subscript if the optional is non-nil. 
This is very similar to placing an exclamation mark (!) 
after an optional value to force the unwrapping of its 
value. The main difference is that optional chaining fails 
gracefully when the optional is nil, whereas forced 
unwrapping triggers a runtime error when the optional is 
nil.
  • 在想調用的屬性、方法、或下標腳本的可選值后面放一個?,可以定義一個可選鏈。這很像在可選值后面放一個!來強制拆得其封包內的值。它們的主要的區別在于當可選值為空時可選鏈即刻失敗,然而一般的強制解析將會引發運行時錯誤。

例子:

class Residence {
    var numberOfRooms = 1;
}

class Person {
    var residence: Residence?;
}
let john = Person();
let rootCount = john.residence!.numberOfRooms;

執行結果:

fatal error: unexpectedly found nil while unwrapping an Optional value

我們改寫成可選鏈的方式去訪問numberOfRooms:

let john = Person();
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.

通過可選鏈調用屬性(Accessing Properties Through Optional Chaining)

例子:

class Person {
    var residence: Residence?;
}

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

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

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

let john = Person();
if let roomCount = john.residence?.numberOfRooms {
    print("John's residence has \(roomCount) room(s).");
} else {
    print("Unable to retrieve the number of rooms.");
}

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.");
}

執行結果:

Unable to retrieve the number of rooms.
John's residence has 0 room(s).

通過可選鏈調用方法(Calling Methods Through Optional Chaining)

You can use optional chaining to call a method on an optional value, 
and to check whether that method call is successful. You can do this 
even if that method does not define a return value.
  • 可以使用可選鏈來調用方法去判斷是否方法調用成功。即使該方法沒有返回值。

例子:

let john = Person();
john.residence = Residence();
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.")
}

執行結果:

It was possible to print the number of rooms.

使用可選鏈調用下標腳本(Accessing Subscripts Through Optional Chaining)

You can use optional chaining to try to retrieve and set a value from a 
subscript on an optional value, and to check whether that subscript 
call is successful.
  • 可以使用可選鏈嘗試從下標腳本獲取值并且檢查是否調用成功。

例子:

let john = Person();
john.residence = Residence();
let room:Room = Room(name:"xz");
john.residence?.rooms.append(room);
if let firstRoomName = john.residence?[0].name {
    print("The first room name is \(firstRoomName).")
} else {
    print("Unable to retrieve the first room name.")
}

執行結果:

The first room name is xz.

連接多層鏈接(Linking Multiple Levels of Chaining)

You can link together multiple levels of optional chaining to drill 
down to properties, methods, and subscripts deeper within a model. 
However, multiple levels of optional chaining do not add more levels of 
optionality to the returned value.
  • 可以將多層可選鏈連接在一起,可以掘取模型內更下層的屬性方法和下標腳本。然而多層可選鏈不能再添加比已經返回的可選值更多的層。

例子:

let john = Person();
john.residence = Residence();
john.residence?.address = Address();
john.residence?.address?.street = "beijing road";
if let johnsStreet = john.residence?.address?.street {
    print("John's street name is \(johnsStreet).");
} else {
    print("Unable to retrieve the address.");
}

執行結果:

John's street name is beijing road.

鏈接可選返回值的方法(Chaining on Methods with Optional Return Values)

例子:

let john = Person();
john.residence = Residence();
john.residence?.address = Address();
john.residence?.address?.street = "beijing road";
john.residence?.address?.buildingName = "beijing building";

if let buildingIdentifier = john.residence?.address?.buildingIdentifier()?.uppercased() {
    print("John's building identifier is \(buildingIdentifier).");
}

執行結果:

John's building identifier is BEIJING BUILDING.
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容