Swift 可选链

Swift 可选链(Optional Chaining)是一种可以请求和调用属性、方法和子脚本的过程,用于请求或调用的目标可能是nil。

可选链返回两个值:

  • 如果目标有值,调用就会成功,返回该值
  • 如果目标为nil,调用将返回nil

多次请求或调用可以被链接成一个链,如果任意一个节点为nil将导致整条链失效。

可选链科代替强制解析

通过在属性、方法、或下标脚本 的可选值后面放一个问号 ? ,即可定义一个可选链

可选链 ? 感叹韩 (!)强制展开方法,属性,下标脚本可选链
?放置于可选值后来调用方法,属性,下标脚本 !放置于可选值后来调用方法,属性,下表脚本来强制展开值
当可选为nil输出比较友好的错误信息 当可选为nil时强制执行错误
使用感叹号(!)可选链实例
class Person {
    var residence: Residence?
}

class Residence {
    var numberOfRooms = 1
}

let john = Person()

//将导致运行时错误
let roomCount = john.residence!.numberOfRooms

上述程序运行后报错:

fatal error: unexpectedly found nil while unwrapping an Optional value

想要使用 ! 强制解析或得这个人 residence 属性的 numberOfRoom 的属性值,将会引发运行时报错。因为这是没有可以供解析的 reseidence值。

使用问号 (?) 可选链实例
class Person {
    var residence: Residence?
}

class Residence {
    var numberOfRooms = 1
}

let john = Person()

// 链接可选residence?属性,如果residence存在则取回numberOfRooms的值
if let roomCount = john.residence?.numberOfRooms {
    print("John 的房间号为 \(roomCount)。")
} else {
    print("不能查看房间号")
}

以上程序执行输出结果为:

不能查看房间号

因为这种尝试获得numberOfRooms的操作可能失败,可选链会返回 Int? 类型值。或者成为”可选Int“。当residence 是空的时候,选择Int将会为空,因此会出现无法访问numberOfRooms的情况。
要注意的是,即使numberOfRooms是非可选Int (Int?) 时这一点也城里。只要通过可选链的请求就意味着最后numberOfRooms总是返回一个Int? 而不是Int。

为可选链定义模型

你可以使用可选链来多层调用属性、方法、下标脚本。这让你可以利用他们之间复杂的模型来获取更低层的属性,并检查是否可以成功获取此类底层属性。


class Person {
    var residence: Residence?
}

// 定义了一个变量 rooms,它被初始化为一个Room[]类型的空数组
class Residence {
    var rooms = [Room]()
    var numberOfRooms: Int {
        return rooms.count
    }
    subscript(i: Int) -> Room {
        return rooms[i]
    }
    func printNumberOfRooms() {
        print("房间号为 \(numberOfRooms)")
    }
    var address: Address?
}

// Room 定义一个name属性和一个设定room名的初始化器
class Room {
    let name: String
    init(name: String) { self.name = name }
}

// 模型中的最终类叫做Address
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
        }
    }
}

let john = Person()


if ((john.residence?.printNumberOfRooms()) != nil) {
    print("输出房间号")
} else {
    print("无法输出房间号")
}

以上程序执行输出结果为:

无法输出房间号

使用 if 语句来检查是否能成功调用printNumberOfRooms方法:如果方法通过可选链调用成功,printNumberOfRooms的隐式返回值将会是Void,如果没有成功,将返回nil。

使用可选链调用下标脚本

你可以使用可选链来尝试从下标脚本获取值并检查下标脚本的调用是否成功,然而,你不能通过可选链来设置下标脚本

class Person {
    var residence: Residence?
}

// 定义了一个变量 rooms,它被初始化为一个Room[]类型的空数组
class Residence {
    var rooms = [Room]()
    var numberOfRooms: Int {
        return rooms.count
    }
    subscript(i: Int) -> Room {
        return rooms[i]
    }
    func printNumberOfRooms() {
        print("房间号为 \(numberOfRooms)")
    }
    var address: Address?
}

// Room 定义一个name属性和一个设定room名的初始化器
class Room {
    let name: String
    init(name: String) { self.name = name }
}

// 模型中的最终类叫做Address
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
        }
    }
}

let john = Person()
if let firstRoomName = john.residence?[0].name {
    print("第一个房间名 \(firstRoomName).")
} else {
    print("无法检索到房间")
}

输出结果为:

无法检索到房间
通过可选链接调用来访问下标

通过可选链接调用,我们可以用下标来对可选值进行读取或写入,并且判断调用是否成功。

class Person {
    var residence: Residence?
}

// 定义了一个变量 rooms,它被初始化为一个Room[]类型的空数组
class Residence {
    var rooms = [Room]()
    var numberOfRooms: Int {
        return rooms.count
    }
    subscript(i: Int) -> Room {
        return rooms[i]
    }
    func printNumberOfRooms() {
        print("房间号为 \(numberOfRooms)")
    }
    var address: Address?
}

// Room 定义一个name属性和一个设定room名的初始化器
class Room {
    let name: String
    init(name: String) { self.name = name }
}

// 模型中的最终类叫做Address
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
        }
    }
}

let john = Person()

let johnsHouse = Residence()
johnsHouse.rooms.append(Room(name: "客厅"))
johnsHouse.rooms.append(Room(name: "厨房"))
john.residence = johnsHouse

if let firstRoomName = john.residence?[0].name {
    print("第一个房间名为\(firstRoomName)")
} else {
    print("无法检索到房间")
}

以上程序执行输出结果为:

第一个房间名为客厅
访问可选类型的下标

如果下标返回可选空类型值,比如Swift中的Dictionary的key的下标。可以在下标的闭合括号后面放一个问号来链接下标的可空返回值。

var testScores = ["Dave":[86,82,84],"Bev":[79,94,81]]
testScores["Dave"]?[0] = 91
testScores["Bev"]?[0]++
testScores["Brian"]?[0] = 72
// the "Dave" array is now [91, 82, 84] and the "Bev" array is now [80, 94, 81]

上面例子定义了一个testScores数组,包含了两对键值对,把String类型的key映射到一个整型数组。这个例子用可选链接调用把“Dave”数组中第一个元素设为91,把“Bev”数组的第一个元素+1,然后尝试把“Brain”数组中的第一个元素设为72,这一个调用失败。

连接多层连接

你可以将多层可选链连接在一起,可以掘取模型内更下层的属性方法和下标脚本。然而多层可选链接不能再添加比已经返回的可选值更多的层。如果你试图通过可选链接获取Int值,不论使用了多少层链接返回的总是 Int? 。相似的如果你试图通过可选链获取Int? 不论你使用多少层链接返回的总是Int?

对返回可选值的函数进行链接

我们还可以通过可选链接来调用返回可空值的方法,并且可以继续对可选值进行链接。

你可能感兴趣的:(Swift 可选链)