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

可选链返回两个值:

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

  • 如果目标为nil,调用将返回nil

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


可选链可替代强制解析

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

可选链 '?' 感叹号(!)强制展开方法,属性,下标脚本可选链
? 放置于可选值后来调用方法,属性,下标脚本 ! 放置于可选值后来调用方法,属性,下标脚本来强制展开值
当可选为 nil 输出比较友好的错误信息 当可选为 nil 时强制展开执行错误

使用感叹号(!)可选链实例

class Person {
var residence: Residence?
} class Residence {
var numberOfRooms =
} let john = Person() //将导致运行时错误
let roomCount = john.residence!.numberOfRooms

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

fatal error: unexpectedly found nil while unwrapping an Optional value

使用感叹号(!)强制解析获得这个人residence属性numberOfRooms属性值,将会引发运行时错误,因为这时没有可以供解析的residence值。

使用问号(?)可选链实例

class Person {
var residence: Residence?
} class Residence {
var numberOfRooms =
} 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
}
}
}

通过可选链调用方法

你可以使用可选链的来调用可选值的方法并检查方法调用是否成功。即使这个方法没有返回值,你依然可以使用可选链来达成这一目的。

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。


使用可选链调用下标脚本

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

实例1

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?[].name {
print("第一个房间名 \(firstRoomName).")
} else {
print("无法检索到房间")
}

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

无法检索到房间

在下标脚本调用中可选链的问号直接跟在 circname.print 的后面,在下标脚本括号的前面,因为circname.print是可选链试图获得的可选值。

实例2

实例中创建一个Residence实例给john.residence,且在他的rooms数组中有一个或多个Room实例,那么你可以使用可选链通过Residence下标脚本来获取在rooms数组中的实例了:

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 let johnsAddress = Address()
johnsAddress.buildingName = "The Larches"
johnsAddress.street = "Laurel Street"
john.residence!.address = johnsAddress if let johnsStreet = john.residence?.address?.street {
print("John 所在的街道是 \(johnsStreet)。")
} 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?[].name {
print("第一个房间名为\(firstRoomName)")
} else {
print("无法检索到房间")
}

访问可选类型的下标

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

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

上面的例子中定义了一个testScores数组,包含了两个键值对, 把String类型的key映射到一个整形数组。

这个例子用可选链接调用把"Dave"数组中第一个元素设为91,把"Bev"数组的第一个元素+1,然后尝试把"Brian"数组中的第一个元素设为72。

前两个调用是成功的,因为这两个key存在。但是key"Brian"在字典中不存在,所以第三个调用失败。


连接多层链接

你可以将多层可选链连接在一起,可以掘取模型内更下层的属性方法和下标脚本。然而多层可选链不能再添加比已经返回的可选值更多的层。

如果你试图通过可选链获得Int值,不论使用了多少层链接返回的总是Int?。 相似的,如果你试图通过可选链获得Int?值,不论使用了多少层链接返回的总是Int?。

实例1

下面的例子试图获取john的residence属性里的address的street属性。这里使用了两层可选链来联系residence和address属性,它们两者都是可选类型:

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 johnsStreet = john.residence?.address?.street {
print("John 的地址为 \(johnsStreet).")
} else {
print("不能检索地址")
}

实例2

如果你为Address设定一个实例来作为john.residence.address的值,并为address的street属性设定一个实际值,你可以通过多层可选链来得到这个属性值。

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("房间号为 \(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
}
}
}
let john = Person()
john.residence?[] = Room(name: "浴室") let johnsHouse = Residence()
johnsHouse.rooms.append(Room(name: "客厅"))
johnsHouse.rooms.append(Room(name: "厨房"))
john.residence = johnsHouse if let firstRoomName = john.residence?[].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() if john.residence?.printNumberOfRooms() != nil {
print("指定了房间号)")
} else {
print("未指定房间号")
}

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

未指定房间号

wift 可选链

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

可选链返回两个值:

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

  • 如果目标为nil,调用将返回nil

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


可选链可替代强制解析

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

可选链 '?' 感叹号(!)强制展开方法,属性,下标脚本可选链
? 放置于可选值后来调用方法,属性,下标脚本 ! 放置于可选值后来调用方法,属性,下标脚本来强制展开值
当可选为 nil 输出比较友好的错误信息 当可选为 nil 时强制展开执行错误

使用感叹号(!)可选链实例

Swift 可选链的更多相关文章

  1. 学习Swift -- 可选链

    可空链式调用 可空链式调用是一种可以请求和调用属性.方法及下标的过程,它的可空性体现于请求或调用的目标当前可能为空(nil).如果可空的目标有值,那么调用就会成功:如果选择的目标为空(nil),那么这 ...

  2. Swift 可选链-备

    在Swift程序表达式中会看到问号(?)和感叹号(!),它们代表什么含义呢?这些符号都与可选类型和可选链相关,下面来看看可选链. 可选链: 类图: 它们之间是典型的关联关系类图.这些类一般都是实体类, ...

  3. Swift可选链

    //可选链测试 class Person{ var residence:Residence! var name:String init(name:String){ self.name = name } ...

  4. Swift中的可选链与内存管理(干货系列)

    干货之前:补充一下可选链(optional chain) class A { var p: B? } class B { var p: C? } class C { func cm() -> S ...

  5. 【Swift学习】Swift编程之旅---可选链(二十一)

    可选链Optional Chaining是一种可以在当前值可能为nil的可选值上请求和调用属性.方法及下标的方法.如果可选值有值,那么调用就会成功:如果可选值是nil,那么调用将返回nil.多个调用可 ...

  6. swift 注意事项 (十六) —— 可选链

    可选链(Optional Chaining) 我们都知道"可选型"是什么.那么可选链又是什么,举个样例解释一下: struct MyName{      var name } st ...

  7. swift 学习- 19 -- 可选链式调用

    // 可选链式调用 是一种在当前值可能为 nil 的可选值上请求 和 调用属性, 方法以及下标, 如果 可选值有值, 那么调用就会成功, 如果可选值是 nil, 那么就会将返回 nil , // 多个 ...

  8. 《从零开始学Swift》学习笔记(Day 26)——可选链

    原创文章,欢迎转载.转载请注明:关东升的博客 在Swift程序表达式中会看到问号(?)和感叹号(!),它们代表什么含义呢?这些符号都与可选类型和可选链相关,下面来看看可选链. 可选链: 类图: 它们之 ...

  9. Swift的可选链,类型转换和扩展

    可选链(Optional Chaining) 可选链是一种请求或调用属性.方法,子脚本的过程. 可选性体现于请求或调用的目标当前可能为nil.若不为nil则成功调用.否则返回nil并将链失效. 调用可 ...

随机推荐

  1. [LeetCode] 219. Contains Duplicate II ☆(存在重复元素2)

    每天一算:Contains Duplicate II 描述 给出1个整形数组nums和1个整数k,是否存在索引i和j,使得nums[i] == nums[j] 且i和j之间的差不超过k Example ...

  2. linux在线安装jdk,tomcat,Nginx

    安装jdk yum search java 查看java的所有版本内容 yum install -y java版本 -openjdk 安装成功 安装tomcat yum search tomcat y ...

  3. ubuntu python3虚拟环境

    mkvirtualenv flow_chart -p /usr/bin/python3.6 #  命令    环境名    -p   python所在路径 pip install -r request ...

  4. 挖矿病毒watchbog处理过程

    1 挖矿病毒watchbog处理过程 简要说明 这段时间公司的生产服务器中了病毒watchbog,cpu动不动就是100%,查看cpu使用情况,发现很大一部分都是us,而且占100%左右的都是进程wa ...

  5. Centos7下安装MongoDB4.0.10

    前言 模式自由 :可以把不同结构的文档存储在同一个数据库里 面向集合的存储:适合存储 JSON风格文件的形式 完整的索引支持:对任何属性可索引 复制和高可用性:支持服务器之间的数据复制,支持主-从模式 ...

  6. jmeter非GUI的运行命令

    jmeter 的参数 参数说明: -h 帮助 -> 打印出有用的信息并退出 -n 非 GUI 模式 -> 在非 GUI 模式下运行 JMeter -t 测试文件 -> 要运行的 JM ...

  7. 《流畅的Python》Data Structures--第7章 colsure and decorator

    Function Decorators and Closures 装饰器是用于增强函数的行为,理解它,就必须先理解闭包. Python3引入关键字nonlocal,如果要理解闭包,就必须了解它的所有方 ...

  8. python ini文件内容的读取

    (1)新建一个项目,再次新建一个文件 test_cfg.ini (2)再次新建 get_test_cfg.py,用来读取/写入/更改 ini的文件内容 #!/usr/bin/env python # ...

  9. js中in关键字的使用方法

    1.for...in 对数组或对象的循环/迭代操作 对于数组循环出来的是数组元素:对于对象循环出来的是对象属性 2.判断对象是否是数组/对象的元素/属性 格式:(变量 in 对象) 当‘对象’是数组时 ...

  10. Python中的猴子补丁

    monkey patch指的是在运行时动态替换,一般是在startup的时候.用过gevent就会知道,会在最开头的地方gevent.monkey.patch_all();把标准库中的thread/s ...