由此需要注意,可选型操作链的返回结果应该是可选型的预期返回结果。比如如果预期返回 Int 类型数据,那么经过可选型操作链返回的结果应该是 Int?。
下面的例子展示了可选型操作链和强制解包的区别。
classPerson{ var residence: Residence? }
classResidence{ var numberOfRooms =1 }
定义两个类,Person 有一个 Residence 实例作为属性,它是可选的,所以在实例化 Person 时它没有被初始化,它将是 nil。
let john =Person()
let roomCount = john.residence!.numberOfRooms // this triggers a runtime error
这是强制解包操作,它会触发一个运行时错误,原因是 john 的 residence 属性没有被初始化,还不能访问它的属性。使用可选型操作链可以处理这个情况。
iflet 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."
john.residence =Residence()
iflet 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)."
定义模型类以展示可选型操作链的使用场景
下面对 Person 和 Residence 类进行重构,并添加 Room 和 Address 类。
classPerson{ var residence: Residence? }
classResidence{ var rooms = [Room]() var numberOfRooms: Int { return rooms.count } subscript(i: Int) -> Room { get { return rooms[i] } set { rooms[i] = newValue } } funcprintNumberOfRooms() { print("The number of rooms is \(numberOfRooms)") } var address: Address? }
classRoom{ let name: String init(name: String) { self.name = name } }
classAddress{ var buildingName: String? var buildingNumber: String? var street: String? funcbuildingIdentifier() -> String? { iflet buildingNumber = buildingNumber, let street = street { return"\(buildingNumber)\(street)" } elseif buildingName !=nil { return buildingName } else { returnnil } } }
let john =Person() iflet 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."
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."
使用可选型操作链访问下标
使用可选型操作链访问下标时要注意问号必须在变量名的后面,在下标的前面。
iflet 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."
iflet 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]
多级链
你可以链接很长一串操作。
iflet 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."
iflet 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."
iflet buildingIdentifier = john.residence?.address?.buildingIdentifier() { print("John's building identifier is \(buildingIdentifier).") } // Prints "John's building identifier is The Larches."
iflet 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"."