【iOS】Swift系列十五 - 可选链

多个可选类型组合在一起调用就会形成可选链条。

一、可选链(Optional Chaining)

1.1. 什么是可选链

示例代码:

1
2
3
4
5
6
7
8
9
10
class Car { var price = 0 }
class Dog { var weight = 0 }
class Person {
var name: String = ""
var dog: Dog = Dog()
var car: Car? = Car()
func age() -> Int { 30 }
func eat() { print("Person eat") }
subscript(index: Int) -> Int { index }
}

正常调用:

1
2
3
var person: Person = Person()
person.name = "idbeny"
person.age()
  1. 如果把person对象修改为可选类型:

  2. 系统提示要想用可选类型对象引用成员必须强制解包或添加?

  3. 按照提示修改代码,编译通过:

    1
    2
    3
    4
    5
    var person: Person? = Person()
    var age = person?.age()
    var age1 = person!.age()
    var name = person!.name = "idbeny"
    var index = person?[6]
  • age是可选类型Int?,打印Optional(30)
  • age1Int类型,打印18
  • name是可选类型String?,打印Optional("idbeny")
  • index是可选类型Int?,打印Optional(6)
  1. 函数返回值:
    1
    2
    func getName() -> String { "idbeny" }
    person?.name = getName()
    如果personnil,就不会调用函数getName()

总结:

  • 如果可选项为nil,调用方法、下标、属性失败,结果为nil
  • 如果可选项不为nil,调用方法、下标、属性成功,结果会被包装成可选项
  • 如果结果本来就是可选项,不会进行再次包装

1.2. 可选项绑定

对象调用函数,是可以用一个变量去接受的,即使函数没有返回值:

1
var result = person?.eat()

result是什么呢?如果personnilresult就是nil;如果person不为nil,则返回一个空元祖(因为Void本质就是一个空元祖)。

怎样知道eat函数是否调用成功?可以使用可选项绑定进行解包判断:

1
2
3
4
5
if let _ = person?.eat() {
print("调用成功")
} else {
print("调用失败")
}

1.3. 可选链

多个?可以链接在一起形成可选链代码:

1
2
3
var dog = person?.dog // Dog?
var weight = person?.dog.weight // Int?
var price = person?.car?.price // Int?

如果链中任何一个节点是nil,那么整个链就会调用失败。可选链最终返回的都是可选类型(不强制解包的情况下)。

二、可选链应用

示例代码一:

1
2
3
4
5
6
7
8
9
var scores = ["idbeny": [10, 20, 30], "1024星球": [66, 88, 99]]
scores["idbeny"]?[0] = 100
print(scores) // 输出:["idbeny": [100, 20, 30], "1024星球": [66, 88, 99]]

scores["1024星球"]?[2] += 11
print(scores) // 输出:["idbeny": [100, 20, 30], "1024星球": [66, 88, 110]]

scores["test"]?[0] = 666
print(scores) // 输出:["idbeny": [100, 20, 30], "1024星球": [66, 88, 110]]

字典取值都是可选类型,因为key有可能为nil。所以字典取值一般加上一个?,尽量不要使用!强制解包,防止取出的值是nil

示例代码二:

1
2
3
4
5
var num1: Int? = 5
num1? = 10 // Optional(10)

var num2: Int? = nil
num2? = 10 // nil

num1? = 10意思是如果num1不为nil,就把10赋值给num1,并且包装为可选类型。

num2? = 10意思是如果num2nil,后面的代码就不会执行。

示例代码三:

1
2
3
4
5
6
var dict: [String: (Int, Int) -> Int] = [
"sum": (+),
"diff": (-)
]
var result = dict["sum"]?(10, 20)
print(result) // 输出:Optional(30)

(+)是把两个参数相加并返回的意思,是编译器的语法糖。字典取值如果是函数,该函数也会被包装成可选类型,所以需要?调用函数,但是最终函数返回值是可选类型。