通过在想调用的属性、方法、或子脚本后面的可选值放一个问号,可以定义一个可选链接。这一点很像在可选链接后面放一个声明符号来强制拆得其封包内的值。他们的主要的区别在于当可选值为空时可选链接即刻失败,然而一般的强制拆包将会引发运行时错误。
下面几段代码将解释自判断链接和强制拆包的不同。
// 1、首先定义两个类Person和Residence。 class Person { var residence: Residence? // 可选值 } class Residence { var numberOfRooms = 1 } let john = Person() // 此时john.residence == nil // 2、如果此时使用声明符!强制拆包获得这个人residence属性的numberOfRooms属性值,将会引发运行时错误,因为这时没有可以供拆包的residence值。 let roomCount = john.residence!.numberOfRooms // this triggers a runtime error” //将导致运行时错误
利用可选链,使用?来代替原来!的位置:
if let roomCount = john.residence?.numberOfRooms { println("John's residence has \(roomCount) room(s).") } else { println("Unable to retrieve the number of rooms.") } // 打印 "Unable to retrieve the number of rooms.
定义一个Residence实例给john.residence,这样它就不再为空了:
john.residence = Residence() john.residence
// 现在有了实际存在的实例而不是nil了。如果你想使用和前面一样的自判断链接来获得numberOfRoooms,它将返回一个包含默认值1的Int?: if let roomCount = john.residence?.numberOfRooms { println("\(roomCount)") } else { println("Unable to retrieve the number of rooms.") } // 打印 "1"。
class Person { var residence: Residence? } class Residence { var rooms = [Room]() // 一个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 buildingName != nil { return buildingName } else if buildingNumber != nil { return buildingNumber } else { return nil } } }
可以利用可选链的可选值获取属性,并且检查属性是否获取成功。但是不能使用可选链为属性赋值。
使用上述定义的类来创建一个人实例,并再次尝试后去它的numberOfRooms属性:
let john = Person() if let roomCount = john.residence?.numberOfRooms { println("John's residence has \(roomCount) room(s).") } else { println("Unable to retrieve the number of rooms.") } // 打印 "Unable to retrieve the number of rooms。
由于john.residence是空,所以这个自判断链接和之前一样失败了,但是没有运行时错误。
使用可选链来调用方法并检查方法调用是否成功。即使这个方法没有返回值,你依然可以使用可选链来达成这一目的。
func printNumberOfRooms(){ println(“The number of rooms is \(numberOfRooms)”) }
这个方法没有返回值。但是,没有返回值类型的函数和方法有一个隐式的返回值类型Void
利用可选链调用此方法,这个方法的返回值类型将是Void?,而不是Void,因为当通过可选链调用方法时返回值总是自判断类型。
if john.residence?.printNumberOfRooms() != nil{ println("It was possible to print the number of rooms.") } else { println("It was not possible to print the number of rooms.") } // 打印 "It was not possible to print the number of rooms."。
注意: 当你使用可选链来获取子脚本的时候,你应该将问号放在子脚本括号的前面而不是后面。可选链的问号一般直接跟在可选表达语句的后面。
下面这个例子用在Residence类中定义的子脚本来获取john.residence数组中第一个房间的名字。因为john.residence现在是nil,子脚本的调用失败了。
if let firstRoomName = john.residence?[0].name { println("\(firstRoomName)") } else { println("Unable") } // 打印 "Unable"。
下面创建一个Residence实例给john.residence
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."
2015-03-24
20:10:15