Swift 可选链
可选链(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 可选链的更多相关文章
- 学习Swift -- 可选链
可空链式调用 可空链式调用是一种可以请求和调用属性.方法及下标的过程,它的可空性体现于请求或调用的目标当前可能为空(nil).如果可空的目标有值,那么调用就会成功:如果选择的目标为空(nil),那么这 ...
- Swift 可选链-备
在Swift程序表达式中会看到问号(?)和感叹号(!),它们代表什么含义呢?这些符号都与可选类型和可选链相关,下面来看看可选链. 可选链: 类图: 它们之间是典型的关联关系类图.这些类一般都是实体类, ...
- Swift可选链
//可选链测试 class Person{ var residence:Residence! var name:String init(name:String){ self.name = name } ...
- Swift中的可选链与内存管理(干货系列)
干货之前:补充一下可选链(optional chain) class A { var p: B? } class B { var p: C? } class C { func cm() -> S ...
- 【Swift学习】Swift编程之旅---可选链(二十一)
可选链Optional Chaining是一种可以在当前值可能为nil的可选值上请求和调用属性.方法及下标的方法.如果可选值有值,那么调用就会成功:如果可选值是nil,那么调用将返回nil.多个调用可 ...
- swift 注意事项 (十六) —— 可选链
可选链(Optional Chaining) 我们都知道"可选型"是什么.那么可选链又是什么,举个样例解释一下: struct MyName{ var name } st ...
- swift 学习- 19 -- 可选链式调用
// 可选链式调用 是一种在当前值可能为 nil 的可选值上请求 和 调用属性, 方法以及下标, 如果 可选值有值, 那么调用就会成功, 如果可选值是 nil, 那么就会将返回 nil , // 多个 ...
- 《从零开始学Swift》学习笔记(Day 26)——可选链
原创文章,欢迎转载.转载请注明:关东升的博客 在Swift程序表达式中会看到问号(?)和感叹号(!),它们代表什么含义呢?这些符号都与可选类型和可选链相关,下面来看看可选链. 可选链: 类图: 它们之 ...
- Swift的可选链,类型转换和扩展
可选链(Optional Chaining) 可选链是一种请求或调用属性.方法,子脚本的过程. 可选性体现于请求或调用的目标当前可能为nil.若不为nil则成功调用.否则返回nil并将链失效. 调用可 ...
随机推荐
- 离线yum源挂载及yum服务器搭建
在进行现网环境搭建的时候,绝大多数情况下,centos或redhat(以下以centos为例)服务器是跟公网隔离的,因此需要找一台服务器挂载自己的yum源. 一.离线yum源包的制作 离线yum源可以 ...
- Linux用户管理——useradd
除了useradd还有一个命令adduser,两者是链接关系 [root@51cto ~]# which adduser /usr/sbin/adduser [root@51cto ~]# which ...
- python-----批量操作xml文件(新建、增、删、改、查)
最近需要处理xml文件,学习并整理了一些常用的操作,代码如下: #!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2019/7/9 15: ...
- Codeforces 567C - Geometric Progression - [map维护]
题目链接:https://codeforces.com/problemset/problem/567/C 题意: 给出长度为 $n$ 的序列 $a[1:n]$,给出公比 $k$,要求你个给出该序列中, ...
- ndk学习之C语言基础复习----虚拟内存布局与malloc申请
在这一次中来学习一下C语言的内存布局,了解它之后就可以解释为啥在用malloc()申请的内存之后需要用memset()来对内存进行一下初始化了,首先来了解一下物理内存与虚拟内存: 物理内存:通过物理内 ...
- jmeter非GUI的运行命令
jmeter 的参数 参数说明: -h 帮助 -> 打印出有用的信息并退出 -n 非 GUI 模式 -> 在非 GUI 模式下运行 JMeter -t 测试文件 -> 要运行的 JM ...
- Android-File读写+SharedPreferences的存取地址
写了两个demo,一个是使用SharedPreferences将数据存储在应用文件中并读取,另一个是使用Context的openFileOutput和openFileInput将数据存储在应用文件中并 ...
- Disconnected from the target VM, address: '127.0.0.1:56577', transport: 'socket'
Disconnected from the target VM, address: '127.0.0.1:56577', transport: 'socket' Disconnected from t ...
- VisualGC,JVMStat安装配置
通过VisualGC工具可以通过图形化方式查看JVM垃圾收集的情况. http://www.oracle.com/technetwork/java/jvmstat-142257.html 下载 htt ...
- java获取一段字符串里符合日期的正则表达式的字符串
import java.util.regex.Matcher; import java.util.regex.Pattern; public class Test3 { public static v ...