为什么需求Optional
Swift中引入了可选项(Optional)的概念是为了解决在代码中关于某些变量或常量可能为nil的情况进行处理,然后减少了程序中的不确认性,使得程序更加稳定和安全。
什么是Optional
在Swift中,可选项的类型是运用?来表明的,例如String?即为一个可选的字符串类型,表明这个变量或常量可能为nil。而关于不可选项,则直接运用相应类型的称号,例如String表明一个非可选的字符串类型。
var str: String = nil
var str1: String? = nil
Optional实现原理
Optional实际上是Swift语言中的一种枚举类型。在Swift中声明Optional类型时,编译器会主动将其转换成对应的枚举类型,例如:
var optionalValue: Int? = 10
// 等价于:
enum Optional<Int> {
case none
case some(Int)
}
var optionalValue: Optional<Int> = .some(10)
在上面的代码中,咱们声明了一个Optional类型的变量optionalValue,并将其初始化为10。实际上,编译器会主动将其转换为对应的枚举类型,即Optional枚举类型的.some(Int),其间的Int便是咱们所声明的可选类型的相关值。
当咱们在运用Optional类型的变量时,能够经过判别其枚举值是.none仍是.some来确认它是否为nil。假如是.none,表明该Optional值为空;假如是.some,就能够经过拜访其相关值获取详细的数值。
Optional的源码实现为:
@frozen public enum Optional<Wrapped> : ExpressibleByNilLiteral {
case none
case some(Wrapped)
}
- Optioanl其实是规范库里的一个enum类型
- 用规范库实现语言特性的典型
- Optional.none 便是nil
- Optional.some 便是包装了实际的值
- 泛型特点 unsafelyUnwrapped
- 理论上咱们能够直接调用unsafelyUnwrapped获取可选项的值
Optional的解包办法
1. 可选项绑定(Optional Binding)
运用 if let 或许 guard let 语句来判别 Optional 变量是否有值,假如有值则解包,并将其赋值给一个非可选类型的变量。
var optionalValue: Int? = 10
// 可选项绑定
if let value = optionalValue {
print("Optional value is \(value)")
} else {
print("Optional value is nil")
}
可选项绑定语句有两个分支:if分支和else分支。假如 optionalValue 有值,if 分支就会被履行,unwrappedValue 就会被赋值为 optionalValue 的值。不然,履行 else 分支。
2. 强制解包(Forced Unwrapping)
运用!来获取一个不存在的可选值会导致运行过错,在运用!强制展开之前有必要保证可选项中包括一个非nil的值
var optionalValue: Int? = 10
let nonOptionalValue = optionalValue! // 解包optionalValue值
print(nonOptionalValue) // 输出:10
需求留意的是,假如 Optional 类型的值为 nil,运用强制解包办法解包时,会导致运行时过错 (Runtime Error)。
3. 隐式解包(Implicitly Unwrapped Optionals)
在界说 Optional 类型变量时运用 ! 操作符,标明该变量能够被隐式解包。用于在一些情况下,咱们能够确认该 Optional 变量绑定后不会为 nil,能够快捷的解包而不用每次都运用 ! 或许 if let 进行解包。
var optionalValue: Int! = 10
let nonOptionalValue = optionalValue // 隐式解包
print(nonOptionalValue) // 输出:10
需求留意的是,隐式解包的 Optional 假如 nil 的话,会导致 runtime error,所以运用隐式解包 Optional 需求保证其一直有值,不然仍是需求检查其非 nil 后再操作。
总的来说,咱们应该尽量避免运用强制解包,而是经过可选项绑定来处理 Optional 类型的值,在需求运用隐式解包的情况下,也要保证其可靠性和稳定性,尽量减少出现运行时过错的概率。
可选链(Optional Chaining)
是一种在 Optional 类型值上进行操作的办法,能够将多个 Optional 值的处理放在一同,并在任何一个 Optional 值为 nil 的时刻中止处理。
经过在 Optional 类型值后边跟上问号 ?,咱们就能够运用可选链来拜访该 Optional 目标的特点和办法。
class Person {
var name: String
var father: Person?
init(name: String, father: Person?) {
self.name = name
self.father = father
}
}
let father = Person(name: "Father", father: nil)
let son = Person(name: "Son", father: father)
// 可选链调用特点
if let fatherName = son.father?.name {
print("Father's name is \(fatherName)") // 输出:Father's name is Father
} else {
print("Son without father")
}
// 可选链调用办法
if let count = son.father?.name.count {
print("Father's name has \(count) characters") // 输出:Father's name has 6 characters
} else {
print("Son without father")
}
在上面的代码中,咱们界说了一个 Person 类,并初始化了一个包括父亲(father)的儿子(son)目标。其间,父亲目标的father特点为nil。咱们运用问号 ? 来符号 father 目标为 Optional 类型,以避免拜访 nil 目标时的运行时过错。
需求留意的是,假如一个 Optional 类型的特点经过可选链调用后,返回值不是 Optional 类型,那么在可选链调用后,就不再需求加问号 ? 符号其为 Optional 类型了。
class Person {
var name: String
var age: Int?
init(name: String, age: Int?) {
self.name = name
self.age = age
}
func printInfo() {
print("\(name), \(age ?? 0) years old")
}
}
let person = Person(name: "Tom", age: nil)
// 可选链调用办法后,返回值不再是 Optional 类型
let succeed = person.printInfo() // 输出:Tom, 0 years old
在上面的代码中,咱们界说了一个 Person 类,并初始化了一个包括年纪(age)的人(person)目标。在可选链调用目标的办法——printInfo() 办法后,因为该办法返回值不是 Optional 类型,所以 returnedValue 就不再需求加问号 ? 符号其为 Optional 类型了。
Optional 的嵌套
将一个 Optional 类型的值作为另一个 Optional 类型的值的成员,构成嵌套的 Optional 类型。
var optionalValue: Int? = 10
var nestedOptionalValue: Int?? = optionalValue
在上面的代码中,咱们界说了一个 Optional 类型的变量 optionalValue,并将其赋值为整型变量 10。然后,咱们将 optionalValue 赋值给了另一个 Optional 类型的变量 nestedOptionalValue,构成了一个嵌套的 Optional 类型。
在处理嵌套的 Optional 类型时,咱们需求特别当心,因为它们的运用很简单造成逻辑上的混杂和过错。为了解决这个问题,咱们能够运用 Optional Binding 或许 ?? 操作符(空兼并运算符)来降低 Optional 嵌套的复杂度。
var optionalValue: Int? = 10
var nestedOptionalValue: Int?? = optionalValue
// 两层可选项绑定
if let nestedValue = nestedOptionalValue, let value = nestedValue {
print(value) // 输出:10
} else {
print("Optional is nil")
}
// 空兼并运算符
let nonOptionalValue = nestedOptionalValue ?? 0
print(nonOptionalValue) // 输出:Optional(10)
在上面的代码中,咱们运用了两层可选项绑定来判别 nestedOptionalValue 是否可绑定,以及其嵌套的 Optional 值是否可绑定,并将该值赋值给变量 value,以避免 Optional 值的嵌套。另外,咱们还能够运用 ?? 操作符(空兼并运算符)来对嵌套的 Optional 值进行默认取值的操作。
需求留意的是,虽然咱们能够运用 ?? 操作符来降低 Optional 值的嵌套,但在详细的实际应用中,咱们应该在设计时尽量避免 Optional 值的嵌套,以便代码的可读性和维护性。假如关于某个变量来说,它的值可能为空,咱们能够考虑运用默认值或许界说一个默认值的 Optional 值来代替嵌套的 Optional 类型。
学习 Swift,勿忘初心,方得一直。但要陷入困境时,也不要忘了最初的梦想和时代所需求的技术。