Skip to content

Optional Chaining

Huan Jie Xu edited this page Jul 21, 2019 · 1 revision

Swift 的可选绑定类似于 OC 中的消息为 nil,但是运用于所有类型,能够被检测成功或失败

Query & Call

Property / Function / Subscript

强制展开的替代方案: 可选绑定

class Person {
    var residence: Residence?
}

class Residence {
    var numberOfRooms = 1
    var rooms = [Room]()
}

// 强制展开,如果可选为 nil 运行时强制解包将会报错
let roomCount = john.residence!.numberOfRooms

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

通过可选绑定访问属性

let someAddress = Address()
someAddress.buildingNumber = "29"
someAddress.street = "Acacia Road"
john.residence?.address = someAddress

由于代码 john.residence = nil,分配可选时 = 右边不执行

func createAddress() -> Address {
    print("Function was called.")

    let someAddress = Address()
    someAddress.buildingNumber = "29"
    someAddress.street = "Acacia Road"

    return someAddress
}
// 不打印 Function was called,既没有调用 createAddress()
john.residence?.address = createAddress()

通过可选绑定访问方法

func printNumberOfRooms() {
    print("The number of rooms is \(numberOfRooms)")
}

// 可选绑定返回 Void? 即使 john.residence != nil,返回值也为空
if john.residence?.printNumberOfRooms() != nil {
// if (john.residence?.address = someAddress) != nil
// 其中无论赋值成不成功,返回值均为 nil
    print("It was possible to print the number of rooms.")
}else {
    print("It was not possible to print the number of rooms.")
}
// Print "It was not possible to print the number of rooms"

通过可选绑定访问下标

  • 放在下标前面
if let firstRoomName = john.residence?[0].name {
    print("The first room name is \(firstRoomName)")
}else {
    print("Unable to retrieve the first room name.")
}
  • 访问可选类型的下标
var testScores = ["Dave": [86, 82, 84], "Bev": [79, 94, 81]]
testScores["Dave"]?[0] = 91
testScores["Bev"]?[0] += 1
testScores["Brian"]?[0] = 72

多级可选

多个查询能够被链接在一起,当连接中的绑定已经为 nil,则整条链失效

  • 如果 optional.Int,始终返回 Int?,无论有多少层
  • 如果 optional.Int?,始终返回 Int?,无论有多少层
if let johnStreet = john.residence?.address?.street {
    print("John's street name is \(johnsStreet).")
}else {
    print("Unable to retrieve the address.")
}
// Prints "John's street name is Laurel Street."

可选绑定方法返回值

if let buildingIdentifier = john.residence?.address?.buildingIdentifier() {
    print("John's building identifier is \(buildingIdentifier).")
}
// Print "John's building identifier is The Larches."

如果需要进一步执行可选返回值

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\"")
    }
}
// Prints "John's building identifier begins with "The"."

由于不是方法本身可选,所以不是在 "()" 前面加问号