可选项响应链(学习笔记)
- 可选项响应链
- 可选项响应链是一个用于访问和调用属性、方法、下标的过程,这些属性、方法、下标可能为
nil
;如果有值就会调用成功,如果响应链中只要有一处为nil
,则整个链就会失败;Swift
中可选项响应链类似于Objective-C
中传递消息nil
,但其可用于任何类型,并且可以检查成功不是失败。
- 可选项响应链是一个用于访问和调用属性、方法、下标的过程,这些属性、方法、下标可能为
- 可选项作为强制解包一种替代方案
示例
class Person { var residence: Residence? } // class Residence { var numberOfRooms = 1 } let john = Person() let roomCount = john.residence!.numberOfRooms // this triggers a runtime error if let roomCount = john.residence?.numberOfRooms { print("John's residence has \(roomCount) room(s).") } else { print("Unable to retrieve the number of rooms.") } // Prints "Unable to retrieve the number of rooms." // 如果你给residence赋值,结果如下 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.") } // Prints "John's residence has 1 room(s)."
- 为可选项响应链定义模型类
- 示例代码块
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 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 let buildingNumber = buildingNumber, let street = street { return "\(buildingNumber) \(street)" } else if buildingName != nil { return buildingName } 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.") } // Prints "Unable to retrieve the number of rooms." // 通过响应链设置值 // 由于此之前并没有为residence设值,为nil,因此用someAddress赋值不会成功 let someAddress = Address() someAddress.buildingNumber = "29" someAddress.street = "Acacia Road" john.residence?.address = someAddress // 上面的情况不好观察,下面用函数会比较好观察 func createAddress() -> Address { print("Function was called.") // let someAddress = Address() someAddress.buildingNumber = "29" someAddress.street = "Acacia Road" // return someAddress } john.residence?.address = createAddress() // 可以发现上面的 "Function was called."不会打印
- 通过可选项调用方法
- 示例代码块
// 本例中方法 printNumberOfRooms() 有一个隐式返回值 `Void` (或者 `()` 即空元组) // 如果是可选的值调用,则返回的是 `Void?`,不是 `Void` // 因此可以用 `if` 语句来判断方法是否调用成功 // 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.") } // Prints "It was not possible to print the number of rooms." // // 如果属性返回是 `Void?`,也可用同样的判断方法 if (john.residence?.address = someAddress) != nil { print("It was possible to set the address.") } else { print("It was not possible to set the address.") } // Prints "It was not possible to set the address."
- 通过可选项访问下标
?
放在[]
之前,总是紧跟表达式之后
if let firstRoomName = john.residence?[0].name { print("The first room name is \(firstRoomName).") } else { print("Unable to retrieve the first room name.") } // Prints "Unable to retrieve the first room name." // `?` 的执行是在紧跟 residence 之后, 在 `[]` 调用之前 john.residence?[0] = Room(name: "Bathroom") // 上面的尝试赋值也会失败,因为 residence 仍然是 nil
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.") } // Prints "The first room name is Living Room."
- 可选类型的下标访问,
?
要写在[]
之后
var testScores = ["Dave": [86, 82, 84], "Bev": [79, 94, 81]] testScores["Dave"]?[0] = 91 testScores["Bev"]?[0] += 1 testScores["Brian"]?[0] = 72 // the "Dave" array is now [91, 82, 84] and the "Bev" array is now [80, 94, 81]
- 连接多层级的响应链
- 如果要获取的值不是可选项,但由于可选响应链,它将会成为可选项
- 如果要获取的值是可选项,也不会因为可选项响应链变成多层可选(类似:??, ???)
if let johnsStreet = john.residence?.address?.street { print("John's street name is \(johnsStreet).") } else { print("Unable to retrieve the address.") } // Prints "Unable to retrieve the address." // 如果你给 address 赋一个值 let johnsAddress = Address() johnsAddress.buildingName = "The Larches" johnsAddress.street = "Laurel Street" john.residence?.address = johnsAddress // if let johnsStreet = 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).") } // Prints "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"." // 注意:`?` 是加在 `()` 之后因为返回值才是可选项,而不是方法名之后