可选链
- 官方的说法是:由多个可选类型组成的一个链条被称为可选链
- 然而他的可选性实际上体现在:我们当前调用的目标可能为空.在我们调用这个目标的时候,如果这个目标有值则调用成功,如果目标没有值,则返回nil
可选链的表现形式:
变量名?.变量名?.变量名
可选链的实现细节
我们先创建几个类,并让这几个类之间产生一定的关系,以此作为例子,来看一下可选链的赋值/取值/调用函数是如何实现的
class Father {
var name = ""
var child : Child? //父亲有一个孩子
}
class Child {
var name = ""
var book : Book? //孩子有一本书
func readBook(){
print("孩子在努力的读书")
}
}
class Book {
var name = "" //书有自己的名字
}
-
利用可选链取值
在可选链的取值过程中,编译器会自动判断每一个可选类型是否有值,如果可选类型有值,那么系统会自动进行解包,如果发现可选类型没有值,那么系统会自动返回一个nil
例:取出父亲的孩子的书的名字
//实例化父亲/孩子/书
let father = Father()
let child = Child()
let book = Book()
//建立三者之间的关系
father.child = child //父亲的孩子是Child()
child.book = book //孩子的书是Book()
book.name = "Swifter" //书的名字是"Swifter"
print(father.child?.book?.name) //可选链的取值结果:Optional(Swifter)
Tips:关于可选链的自动解包
实际上,"father.child?.book?.name"这个链条就已经足以证实可选链的自动解包功能.
这是因为,如果child没有被自动解包,那么他的类型是Optional类型(而不是Child类型),
那么child就不可能调用Child类型中的book属性
反例:取出父亲的孩子的书的名字
//实例化父亲/孩子/书
let father = Father()
let child = Child()
let book = Book()
//建立三者之间的关系
father.child = child //父亲的孩子是Child()
// child.book = book //孩子的书是Book()
book.name = "Swifter" //书的名字是"Swifter"
print(father.child?.book?.name) //可选链的取值结果:nil
key message:
可见,任意一个环节为空的可选值为nil,整个可选链的返回值就为nil
-
利用可选链赋值
在可选链的赋值过程中,编译器会自动判断每一个可选类型是否有值,任意一个环节返回值为nil,则整条语句相当于没有执行,如果所有的可选类型都有值,则系统会自动给可选类型进行解包,解包之后再进行赋值
例:给父亲的孩子买一本书
//实例化父亲/孩子/书
let father = Father()
let child = Child()
let book = Book()
//建立三者之间的关系
father.child = child //父亲的孩子是Child()
child.book = book //孩子的书是Book()
father.child?.book?.name = "Swifter 3.0" //给可选链赋值
print(father.child?.book?.name) //可选链的取值结果:Swifter 3.0
反例:给父亲的孩子买一本书
//实例化父亲/孩子/书
let father = Father()
let child = Child()
let book = Book()
//建立三者之间的关系
father.child = child //父亲的孩子是Child()
// child.book = book //孩子的书是Book()
father.child?.book?.name = "Swifter 3.0"
print(father.child?.book?.name) //可选链的取值结果:nil
-
利用可选链调用函数
在可选链调用函数的过程中,如果可选链中所有的可选类型都有值,则调用函数成功,如果可选链中的某一个可选类型的返回值为nil,则该函数不会被调用(并不会报错)
例:父亲让孩子读书
//实例化父亲/孩子/书
let father = Father()
let child = Child()
//建立三者之间的关系
father.child = child //父亲的孩子是Child()
father.child?.readBook() //结果:函数被调用,控制台打印:孩子在努力的读书
反例:父亲让孩子读书
//实例化父亲/孩子/书
let father = Father()
let child = Child()
//建立三者之间的关系
// father.child = child //父亲的孩子是Child()
father.child?.readBook() //结果:函数不会被调用,控制台无响应