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

一、可选链(Optional Chaining)

1.1. 什么是可选链

示例代码:

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 }
}

正常调用:

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

  3. 系统提示要想用可选类型对象引用成员必须强制解包或添加?
  4. swift 可空类型参数 swift 可选_swift_02

  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. 函数返回值:
func getName() -> String { "idbeny" }
person?.name = getName()

如果personnil,就不会调用函数getName()

总结:

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

1.2. 可选项绑定

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

var result = person?.eat()

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

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

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

1.3. 可选链

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

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

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

二、可选链应用

示例代码一:

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

示例代码二:

var num1: Int? = 5
num1? = 10 // Optional(10)

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

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

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

示例代码三:

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

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