5. Swift 可选类型 Optional.png

数据类型的关键字

T Any AnyClass AnyObject
T 表示泛型,可以指代任何数据类型
Any 表示任何数据类型
AnyClass 表示 class 类型
AnyObject 表示 class 类型的实例

数据类型的分类

在 Swift 中数据类型分为值类型和引用类型,只有是引用类型。其他类型都是值类型,包括整型、浮点型、布尔型、字符型、字符串、元组、数组、字典、集合、枚举等类型本质上都是结构体类型,它们均属于值类型。

如 Swift 中 String 是值类型、NSString 是引用类型。

值类型是在赋值或给函数传递参数时创建一个副本,把副本传递过去,在函数的调用过程中不会影响原始值。
引用类型是在赋值或给函数传递参数时把本身引用传递过去,在函数调用过程中会影响原始数据。

值类型参数不能直接以引用类型传递,如果想要在函数内改变值类型参数的原始值,需要将值类型参数声明为 inout,在使用实例前加上 & 符号。

数据类型的获取

Swift 是一个强类型语言,而强类型语言相对于弱类型语言的一个优点是更加严谨。我们可以通过类型来判断出,实例有哪些特征。

type(of: T) 获取值的类型

  1. var name = "huangjian"
  2. print(type(of: name)) // String

is 检查值的类型

  1. var msg = "Hello"
  2. print(msg is String, msg is Int) // true false

数据类型的转换

as 给值做类型转换(父子类关系)
as? 给值做向下可选类型转换
as! 给值做向下强制类型转换

类型强转

  1. if Int("huangjian") != nil {
  2. print(Int("huangjian")!)
  3. }
  4. if let value = Int("huangjian") {
  5. print(value)
  6. }

备注:[Substring]

可选类型

可选类型 Optional<T> 表示变量可能为 T 类型的值,也可能为 nil 值。

为什么会有可选类型这种设计?历史渊源

  1. int age // 未赋初值,值为 0
  2. bool success // 未赋初值,值为 false

创建字符串的可选类型

  1. let name: String? = "huangjian"
  2. let name: Optional<String> = "huangjian"

可选类型变量的强制解析,在可选类型变量后面加上感叹号 ! 即可

  1. print(name) // Optional("huangjian")
  2. print(name!) // huangjian

使用操作符 ! 去获取值为 nil 的可选变量会有运行时错误,这时需要进行判断,或者赋值给一个临时常量

  1. if name != nil {
  2. print(name!)
  3. }
  4. if let your_name = name {
  5. print(your_name)
  6. }

可选类型的常量,可以在声明后,进行一次初始化赋值

  1. let name: String
  2. name = "huangjian"
  3. let name: String?
  4. name = "huangjian"

备注:还有一种叫自动解析的语法,比如 let name: String! = "" ,但解析与上毫无差别,所以不推荐

可选类型的使用

如果直接获取可选类型的变量,比如 print(name),会有 Xcode 警告,它会建议我们使用下面三种方式处理:
Expression implicitly coerced from ‘String?’ to ‘Any’:

  1. Provide a default value to avoid this warning 设置默认值
  2. Force-unwrap the value to avoid this warning 强制解析
  3. Explicitly cast to ‘Any’ with ‘as Any’ to silence this warning 转换成 Any 类型的变量

有值测试:

  1. let name: String? = "huangjian"
  2. print(name ?? "DefaultName") // [output]: huangjian
  3. print(name!) // [output]: huangjian
  4. print(name as Any) // [output]: Optional("huangjian")
  5. if name != nil {
  6. print(name!) // [output]: huangjian
  7. }
  8. if let your_name = name {
  9. print(your_name) // [output]: huangjian
  10. }

无值测试:

  1. let name: String? = nil
  2. print(name ?? "DefaultName") // [output]: DefaultName
  3. // print(name!) // 运行崩溃
  4. print(name as Any) // [output]: nil
  5. if name != nil {
  6. print(name!) // 不执行
  7. }
  8. if let your_name = name {
  9. print(your_name) // 不执行
  10. }

可选链

可选链(Optional Chaining)是一种可以请求和调用属性、方法和子脚本的过程,用于请求或调用的目标可能为 nil。

可选链返回两个值:

  1. 如果目标有值,调用就会成功,返回该值
  2. 如果目标为 nil,调用将返回 nil

多次请求或调用可以被链接成一个链,如果任意一个节点为 nil 将导致整条链失效。

  1. class Person {
  2. var residence: Residence?
  3. }
  4. class Residence {
  5. var numberOfRooms = 1
  6. func printNumberOfRooms() {}
  7. }
  1. let john = Person()
  2. let roomCount = john.residence!.numberOfRooms
  3. // Fatal error: Unexpectedly found nil while unwrapping an Optional value
  1. let john = Person()
  2. /**
  3. 链接可选 residence? 属性,
  4. 如果 residence 存在则取回 numberOfRooms 的值
  5. */
  6. if let roomCount = john.residence?.numberOfRooms {
  7. print("John's room count is \(roomCount)")
  8. } else {
  9. print("不能查看") // 执行此句
  10. }
  1. let john = Person()
  2. /**
  3. 你可以使用可选链的来调用可选值的方法并检查方法调用是否成功
  4. 即使这个方法没有返回值,你依然可以使用可选链来达成这一目的
  5. */
  6. if john.residence?.printNumberOfRooms() != nil {
  7. print("可以输出")
  8. } else {
  9. print("无法输出") // 执行此句
  10. }

Optional 与 Any 的关系

image.png

  1. nil 不是一种类型

  2. Any 类型的变量不能与 nil 值进行相等判断,只有 Optional 类型的变量才能与 nil 值进行相等判断

错误做法:

  1. let name: String? = nil
  2. let value: Any = name as Any
  3. ///! Comparing non-optional value of type 'Any' to 'nil' always returns false
  4. if value == nil {
  5. print("value is nil.")
  6. } else {
  7. print("value is Not nil.") // run here.
  8. }
  9. type(of: value) == Optional<String>.self // true

正确做法:将 Any 改成 Any?

  1. let name: String? = nil
  2. let value: Any? = name
  3. if value == nil {
  4. print("value is nil.")
  5. } else {
  6. print("value is Not nil.")
  7. }