可选链式调用是一种可以在当前值可能为nil的可选值上请求和调用属性、方法及下标的方法。如果可选值有值,那么调用就会成功;如果可选值是nil,那么调用将返回nil。多个调用可以连接在一起形成一个调用链,如果其中任何一个节点为nil,整个调用链都会失败,即返回nil。
Swift 的可选链式调用和 Objective-C 中向nil发送消息有些相像,但是 Swift 的可选链式调用可以应用于任意类型,并且能检查调用是否成功。
1.使用可选链式调用代替强制展开
- 通过在想调用的属性、方法、或下标的可选值(optional value)后面放一个问号(?),可以定义一个可选链。这一点很像在可选值后面放一个叹号(!)来强制展开它的值。它们的主要区别在于当可选值为空时可选链式调用只会调用失败,然而强制展开将会触发运行时错误。
- 可选链式调用的返回结果与原本的返回结果具有相同的类型,但是被包装成了一个可选值。
class Person { var residence: Residence?; } class Residence { var numberOfRooms = 1; } let john = Person(); let roomCount = john.residence?.numberOfRooms; //nil //john.residence!.numberOfRooms; //fatal error: unexpectedly found nil while unwrapping an Optional value
2.可选链式调用示例
- 通过使用可选链式调用可以调用多层属性、方法和下标。这样可以在复杂的模型中向下访问各种子属性,并且判断能否访问子属性的属性、方法或下标。
class Person { var residence: Residence?; } class Room { let name: String; init(name: String) { self.name = name; } } class Residence { var rooms = [Room](); var address: Address?; 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)"); } } class Address { var buildingName: String?; var buildingNumber: String?; var street: String?; func buildingIdentifier() -> String? { if buildingName != nil { return buildingName; } else if buildingNumber != nil && street != nil { return "(buildingNumber) (street)"; } else { return nil; } } } //通过可选链式调用访问属性 let john = Person(); let someAddress = Address(); //因为john.residence为nil,所以这个可选链式调用会失败 john.residence?.address = someAddress; //nil //通过可选链式调用方法 let john1 = Person(); john1.residence?.printNumberOfRooms(); //不会调用方法 john1.residence = Residence(); john1.residence?.printNumberOfRooms(); //会调用方法 //连接多层可选链式调用 let beginsWithThe = john1.residence?.address?.buildingIdentifier()?.hasPrefix("The"); //nil //通过可选链式调用访问下标 let john3 = Person(); john3.residence?[0] = Room(name: "Bathroom"); //nil
【说明】:可以通过连接多个可选链式调用在更深的模型层级中访问属性、方法以及下标。然而,多层可选链式调用不会增加返回值的可选层级。
- 通过可选链式调用访问一个
Int
值,将会返回Int?
,无论使用了多少层可选链式调用。 - 类似的,通过可选链式调用访问
Int?
值,依旧会返回Int?
值,并不会返回Int??
。