- Swift 教程
- Swift - 首页
- Swift - 概述
- Swift - 环境
- Swift - 基本语法
- Swift - 变量
- Swift - 常量
- Swift - 字面量
- Swift - 注释
- Swift 运算符
- Swift - 运算符
- Swift - 算术运算符
- Swift - 比较运算符
- Swift - 逻辑运算符
- Swift - 赋值运算符
- Swift - 位运算符
- Swift - 其他运算符
- Swift 高级运算符
- Swift - 运算符重载
- Swift - 算术溢出运算符
- Swift - 恒等运算符
- Swift - 范围运算符
- Swift 数据类型
- Swift - 数据类型
- Swift - 整数
- Swift - 浮点数
- Swift - Double
- Swift - 布尔值
- Swift - 字符串
- Swift - 字符
- Swift - 类型别名
- Swift - 可选值
- Swift - 元组
- Swift - 断言和前提条件
- Swift 控制流
- Swift - 决策
- Swift - if 语句
- Swift - if...else if...else 语句
- Swift - if-else 语句
- Swift - 嵌套 if 语句
- Swift - switch 语句
- Swift - 循环
- Swift - for in 循环
- Swift - while 循环
- Swift - repeat...while 循环
- Swift - continue 语句
- Swift - break 语句
- Swift - fallthrough 语句
- Swift 集合
- Swift - 数组
- Swift - 集合
- Swift - 字典
- Swift 函数
- Swift - 函数
- Swift - 嵌套函数
- Swift - 函数重载
- Swift - 递归
- Swift - 高阶函数
- Swift 闭包
- Swift - 闭包
- Swift - 转义和非转义闭包
- Swift - 自动闭包
- Swift 面向对象编程
- Swift - 枚举
- Swift - 结构体
- Swift - 类
- Swift - 属性
- Swift - 方法
- Swift - 下标
- Swift - 继承
- Swift - 重写
- Swift - 初始化
- Swift - 析构
- Swift 高级特性
- Swift - ARC 概述
- Swift - 可选链
- Swift - 错误处理
- Swift - 并发
- Swift - 类型转换
- Swift - 嵌套类型
- Swift - 扩展
- Swift - 协议
- Swift - 泛型
- Swift - 访问控制
- Swift - 函数与方法
- Swift - SwiftyJSON
- Swift - 单例类
- Swift 随机数
- Swift 不透明类型和装箱类型
- Swift 有用资源
- Swift - 在线编译
- Swift - 快速指南
- Swift - 有用资源
- Swift - 讨论
Swift - 可选链
可选链是指对可能为 nil 的可选值查询、调用属性、下标和方法的过程。可选链返回两个值:
如果可选值包含一个值,则调用其相关的属性、方法和下标将返回相应的值。
如果可选值包含 nil 值,则其所有相关的属性、方法和下标都将返回 nil。
由于对方法、属性和下标的多个查询被组合在一起,因此一个链的失败会影响整个链,并导致返回 nil 值。
可选链作为强制解包的替代方案
可选链在可选值后使用“?”来调用属性、方法或下标,前提是可选值返回某些值。
可选链“?” | 访问方法、属性和下标 可选链“!”强制解包。 |
“?”放在可选值之后,用于调用属性、方法或下标。 | “!”放在可选值之后,用于调用属性、方法或下标,强制解包值。 |
当可选值为 nil 时,优雅地失败。 | 当可选值为 nil 时,强制解包会触发运行时错误。 |
使用“!”的可选链程序
示例
class ElectionPoll { var candidate: Pollbooth? } class Pollbooth { var name = "MP" } let cand = ElectionPoll() let candname = cand.candidate!.name
输出
当我们在 playground 中运行上述程序时,我们将得到以下结果:
main/main.swift:10: Fatal error: Unexpectedly found nil while unwrapping an Optional value Current stack trace: 0 libswiftCore.so 0x00007fd880a40dc0 _swift_stdlib_reportFatalErrorInFile + 112 1 libswiftCore.so 0x00007fd88070a191 <unavailable> + 1442193 2 libswiftCore.so 0x00007fd880709eb6 <unavailable> + 1441462 3 libswiftCore.so 0x00007fd880709caa <unavailable> + 1440938 4 libswiftCore.so 0x00007fd8807096d0 _assertionFailure(_:_:file:line:flags:) + 315 6 swift-frontend 0x000055a564ac0b3d <unavailable> + 26479421 7 swift-frontend 0x000055a563df4db9 <unavailable> + 13061561 8 swift-frontend 0x000055a563bc54c6 <unavailable> + 10769606 9 swift-frontend 0x000055a563bc19b6 <unavailable> + 10754486 10 swift-frontend 0x000055a563bc10a7 <unavailable> + 10752167 11 swift-frontend 0x000055a563bc341e <unavailable> + 10761246 12 swift-frontend 0x000055a563bc273d <unavailable> + 10757949 13 swift-frontend 0x000055a563a94a39 <unavailable> + 9521721 14 libc.so.6 0x00007fd880017d90 <unavailable> + 171408 15 libc.so.6 0x00007fd880017dc0 __libc_start_main + 128 16 swift-frontend 0x000055a563a94295 <unavailable> + 9519765 Stack dump: 0. Program arguments: /opt/swift/bin/swift-frontend -frontend -interpret main.swift -disable-objc-interop -color-diagnostics -new-driver-path /opt/swift/bin/swift-driver -empty-abi-descriptor -resource-dir /opt/swift/lib/swift -module-name main 1. Swift version 5.7.3 (swift-5.7.3-RELEASE) 2. Compiling with the current language version 3. While running user code "main.swift" Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it): /opt/swift/bin/swift-frontend(+0x551a103)[0x55a56869a103] /opt/swift/bin/swift-frontend(+0x551802e)[0x55a56869802e] /opt/swift/bin/swift-frontend(+0x551a48a)[0x55a56869a48a] /lib/x86_64-linux-gnu/libc.so.6(+0x42520)[0x7fd880030520] /opt/swift/lib/swift/linux/libswiftCore.so(+0x160195)[0x7fd88070a195] /opt/swift/lib/swift/linux/libswiftCore.so(+0x15feb6)[0x7fd880709eb6] /opt/swift/lib/swift/linux/libswiftCore.so(+0x15fcaa)[0x7fd880709caa] /opt/swift/lib/swift/linux/libswiftCore.so($ss17_assertionFailure__4file4line5flagss5NeverOs12StaticStringV_A2HSus6UInt32VtF+0x13b)[0x7fd88070980b] [0x7fd87ece717e] /opt/swift/bin/swift-frontend(+0x1940b3d)[0x55a564ac0b3d] /opt/swift/bin/swift-frontend(+0xc74db9)[0x55a563df4db9] /opt/swift/bin/swift-frontend(+0xa454c6)[0x55a563bc54c6] /opt/swift/bin/swift-frontend(+0xa419b6)[0x55a563bc19b6] /opt/swift/bin/swift-frontend(+0xa410a7)[0x55a563bc10a7] /opt/swift/bin/swift-frontend(+0xa4341e)[0x55a563bc341e] /opt/swift/bin/swift-frontend(+0xa4273d)[0x55a563bc273d] /opt/swift/bin/swift-frontend(+0x914a39)[0x55a563a94a39] /lib/x86_64-linux-gnu/libc.so.6(+0x29d90)[0x7fd880017d90] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80)[0x7fd880017e40] /opt/swift/bin/swift-frontend(+0x914295)[0x55a563a94295] Illegal instruction (core dumped)
上述程序声明“election poll”作为类名,并包含“candidate”作为成员函数。子类声明为“poll booth”,其成员函数“name”初始化为“MP”。对超类的调用是通过创建带有可选“!”的实例“cand”来初始化的。由于其基类中未声明值,因此存储 nil 值,并通过强制解包过程返回致命错误。
使用“?”的可选链程序
示例
class ElectionPoll { var candidate: Pollbooth? } class Pollbooth { var name = "MP" } let cand = ElectionPoll() if let candname = cand.candidate?.name { print("Candidate name is \(candname)") } else { print("Candidate name cannot be retreived") }
输出
当我们在 playground 中运行上述程序时,我们将得到以下结果:
Candidate name cannot be retreived
上述程序声明“election poll”作为类名,并包含“candidate”作为成员函数。子类声明为“poll booth”,其成员函数“name”初始化为“MP”。对超类的调用是通过创建带有可选“?”的实例“cand”来初始化的。由于其基类中未声明值,因此存储 nil 值,并由 else 处理程序块在控制台中打印。
为可选链定义模型类和访问属性
Swift 4 语言还提供可选链的概念,可以声明多个子类作为模型类。这个概念对于定义复杂的模型和访问属性、方法和下标的子属性非常有用。
示例
class rectangle { var print: circle? } class circle { var area = [radius]() var cprint: Int { return area.count } subscript(i: Int) -> radius { get { return area[i] } set { area[i] = newValue } } func circleprint() { print("The number of rooms is \(cprint)") } var rectarea: circumference? } class radius { let radiusname: String init(radiusname: String) { self.radiusname = radiusname } } class circumference { var circumName: String? var circumNumber: String? var street: String? func buildingIdentifier() -> String? { if circumName != nil { return circumName } else if circumNumber != nil { return circumNumber } else { return nil } } } let rectname = rectangle() if let rectarea = rectname.print?.cprint { print("Area of rectangle is \(rectarea)") } else { print("Rectangle Area is not specified") }
输出
当我们在 playground 中运行上述程序时,我们将得到以下结果:
Rectangle Area is not specified
通过可选链调用方法
示例
class rectangle { var print: circle? } class circle { var area = [radius]() var cprint: Int { return area.count } subscript(i: Int) -> radius { get { return area[i] } set { area[i] = newValue } } func circleprint() { print("Area of Circle is: \(cprint)") } var rectarea: circumference? } class radius { let radiusname: String init(radiusname: String) { self.radiusname = radiusname } } class circumference { var circumName: String? var circumNumber: String? var circumarea: String? func buildingIdentifier() -> String? { if circumName != nil { return circumName } else if circumNumber != nil { return circumNumber } else { return nil } } } let circname = rectangle() if circname.print?.circleprint() != nil { print("Area of circle is specified)") } else { print("Area of circle is not specified") }
输出
当我们在 playground 中运行上述程序时,我们将得到以下结果:
Area of circle is not specified
通过创建名为“circname”的实例来调用在 circle() 子类中声明的 circleprint() 函数。如果函数包含某些值,则该函数将返回值;否则,它将通过检查语句“if circname.print?.circleprint() != nil”返回一些用户定义的打印消息。
通过可选链访问下标
可选链用于设置和检索下标值,以验证对该下标的调用是否返回值。“?”放在下标括号之前,用于访问特定下标上的可选值。
示例 1
class rectangle { var print: circle? } class circle { var area = [radius]() var cprint: Int { return area.count } subscript(i: Int) -> radius { get { return area[i] } set { area[i] = newValue } } func circleprint() { print("The number of rooms is \(cprint)") } var rectarea: circumference? } class radius { let radiusname: String init(radiusname: String) { self.radiusname = radiusname } } class circumference { var circumName: String? var circumNumber: String? var circumarea: String? func buildingIdentifier() -> String? { if circumName != nil { return circumName } else if circumNumber != nil { return circumNumber } else { return nil } } } let circname = rectangle() if let radiusName = circname.print?[0].radiusname { print("The first room name is \(radiusName).") } else { print("Radius is not specified.") }
输出
当我们在 playground 中运行上述程序时,我们将得到以下结果:
Radius is not specified.
在上述程序中,未指定成员函数“radiusName”的实例值。因此,对函数的程序调用将仅返回 else 部分,而要返回值,则必须为特定成员函数定义值。
示例 2
class rectangle { var print: circle? } class circle { var area = [radius]() var cprint: Int { return area.count } subscript(i: Int) -> radius { get { return area[i] } set { area[i] = newValue } } func circleprint() { print("The number of rooms is \(cprint)") } var rectarea: circumference? } class radius { let radiusname: String init(radiusname: String) { self.radiusname = radiusname } } class circumference { var circumName: String? var circumNumber: String? var circumarea: String? func buildingIdentifier() -> String? { if circumName != nil { return circumName } else if circumNumber != nil { return circumNumber } else { return nil } } } let circname = rectangle() circname.print?[0] = radius(radiusname: "Diameter") let printing = circle() printing.area.append(radius(radiusname: "Units")) printing.area.append(radius(radiusname: "Meter")) circname.print = printing if let radiusName = circname.print?[0].radiusname { print("Radius is measured in \(radiusName).") } else { print("Radius is not specified.") }
输出
当我们在 playground 中运行上述程序时,我们将得到以下结果:
Radius is measured in Units.
在上述程序中,指定了成员函数“radiusName”的实例值。因此,对函数的程序调用现在将返回值。
访问可选类型的下标
示例
class rectangle { var print: circle? } class circle { var area = [radius]() var cprint: Int { return area.count } subscript(i: Int) -> radius { get { return area[i] } set { area[i] = newValue } } func circleprint() { print("The number of rooms is \(cprint)") } var rectarea: circumference? } class radius { let radiusname: String init(radiusname: String) { self.radiusname = radiusname } } class circumference { var circumName: String? var circumNumber: String? var circumarea: String? func buildingIdentifier() -> String? { if circumName != nil { return circumName } else if circumNumber != nil { return circumNumber } else { return nil } } } let circname = rectangle() circname.print?[0] = radius(radiusname: "Diameter") let printing = circle() printing.area.append(radius(radiusname: "Units")) printing.area.append(radius(radiusname: "Meter")) circname.print = printing var area = ["Radius": [35, 45, 78, 101], "Circle": [90, 45, 56]] area["Radius"]?[1] = 78 area["Circle"]?[1]-- print(area["Radius"]?[0]) print(area["Radius"]?[1]) print(area["Radius"]?[2]) print(area["Radius"]?[3]) print(area["Circle"]?[0]) print(area["Circle"]?[1]) print(area["Circle"]?[2])
输出
当我们在 playground 中运行上述程序时,我们将得到以下结果:
Optional(35) Optional(78) Optional(78) Optional(101) Optional(90) Optional(44) Optional(56)
可以通过引用其下标值来访问下标的可选值。可以访问为 subscript[0]、subscript[1] 等。首先将“radius”的默认下标值赋值为 [35, 45, 78, 101],并将“Circle”赋值为 [90, 45, 56]]。然后将下标值更改为 Radius[0] 为 78,Circle[1] 为 45。
链接多级链
多个子类也可以通过可选链与其超类的方法、属性和下标链接。
可以链接可选值的多个链
示例
如果检索类型不是可选的,则可选链将返回一个可选值。例如,如果通过可选链检索 String,它将返回 String? 值。
class rectangle { var print: circle? } class circle { var area = [radius]() var cprint: Int { return area.count } subscript(i: Int) -> radius { get { return area[i] } set { area[i] = newValue } } func circleprint() { print("The number of rooms is \(cprint)") } var rectarea: circumference? } class radius { let radiusname: String init(radiusname: String) { self.radiusname = radiusname } } class circumference { var circumName: String? var circumNumber: String? var circumarea: String? func buildingIdentifier() -> String? { if circumName != nil { return circumName } else if circumNumber != nil { return circumNumber } else { return nil } } } let circname = rectangle() if let radiusName = circname.print?[0].radiusname { print("The first room name is \(radiusName).") } else { print("Radius is not specified.") }
输出
当我们在 playground 中运行上述程序时,我们将得到以下结果:
Radius is not specified.
在上述程序中,未指定成员函数“radiusName”的实例值。因此,对函数的程序调用将仅返回 else 部分,而要返回值,则必须为特定成员函数定义值。
如果检索类型已经是可选的,则可选链也将返回一个可选值。例如,如果通过可选链访问 String?,它将返回 String? 值。
示例
class rectangle { var print: circle? } class circle { var area = [radius]() var cprint: Int { return area.count } subscript(i: Int) -> radius { get { return area[i] } set { area[i] = newValue } } func circleprint() { print("The number of rooms is \(cprint)") } var rectarea: circumference? } class radius { let radiusname: String init(radiusname: String) { self.radiusname = radiusname } } class circumference { var circumName: String? var circumNumber: String? var circumarea: String? func buildingIdentifier() -> String? { if circumName != nil { return circumName } else if circumNumber != nil { return circumNumber } else { return nil } } } let circname = rectangle() circname.print?[0] = radius(radiusname: "Diameter") let printing = circle() printing.area.append(radius(radiusname: "Units")) printing.area.append(radius(radiusname: "Meter")) circname.print = printing if let radiusName = circname.print?[0].radiusname { print("Radius is measured in \(radiusName).") } else { print("Radius is not specified.") }
输出
当我们在 playground 中运行上述程序时,我们将得到以下结果:
Radius is measured in Units.
在上述程序中,指定了成员函数“radiusName”的实例值。因此,对函数的程序调用现在将返回值。
对具有可选返回值的方法进行链式操作
可选链也用于访问子类定义的方法。
示例
class rectangle { var print: circle? } class circle { var area = [radius]() var cprint: Int { return area.count } subscript(i: Int) -> radius { get { return area[i] } set { area[i] = newValue } } func circleprint() { print("Area of Circle is: \(cprint)") } var rectarea: circumference? } class radius { let radiusname: String init(radiusname: String) { self.radiusname = radiusname } } class circumference { var circumName: String? var circumNumber: String? var circumarea: String? func buildingIdentifier() -> String? { if circumName != nil { return circumName } else if circumNumber != nil { return circumNumber } else { return nil } } } let circname = rectangle() if circname.print?.circleprint() != nil { print("Area of circle is specified)") } else { print("Area of circle is not specified") }
输出
当我们在 playground 中运行上述程序时,我们将得到以下结果:
Area of circle is not specified