為什么會有Optional
OC中沒有Optional類型,OC中所有對象變量都可以為nil,因為nil
是無類型的指針。在OC中字典、數組、集合都不能放入nil
,nil
只能用在OC對象上面,變量在一定程度上來講便利性較差,但在Swift中卻不同。Swift中nil
和OC中的nil
是有很大區別的。在OC中nil
是指向一個不存在的對象的指針,但是在Swift中,nil
不是指針,只是值缺失的特殊類型,任何類型可選項都可以設置為nil
。所以在Swift中,可以用可選項值為nil
,來表達變量的值缺失,增加了一定的便利性。
Swift中我們在變量類型后面添加 ?
來表示一個可選項,例如:
var name: String? = nil
Optional的實現
Optional其實是一個枚舉類型,我們查看標準庫中代碼可以看到
@frozen public enum Optional<Wrapped> : ExpressibleByNilLiteral {
/// The absence of a value.
///
/// In code, the absence of a value is typically written using the `nil`
/// literal rather than the explicit `.none` enumeration case.
case none
/// The presence of a value, stored as `Wrapped`.
case some(Wrapped)
/// Creates an instance that stores the given value.
public init(_ some: Wrapped)
這個枚舉有兩個值,代碼Optional的兩層意思
- none
代表變量沒有值,即為nil
- some
代表變量有值,值為some
,some
包裝了實際了值
那Optional是如果得到實際的值呢,還是來看標準庫中的代碼,
/// The wrapped value of this instance, unwrapped without checking whether
/// the instance is `nil`.
///
/// The `unsafelyUnwrapped` property provides the same value as the forced
/// unwrap operator (postfix `!`). However, in optimized builds (`-O`), no
/// check is performed to ensure that the current instance actually has a
/// value. Accessing this property in the case of a `nil` value is a serious
/// programming error and could lead to undefined behavior or a runtime
/// error.
///
/// In debug builds (`-Onone`), the `unsafelyUnwrapped` property has the same
/// behavior as using the postfix `!` operator and triggers a runtime error
/// if the instance is `nil`.
///
/// The `unsafelyUnwrapped` property is recommended over calling the
/// `unsafeBitCast(_:)` function because the property is more restrictive
/// and because accessing the property still performs checking in debug
/// builds.
///
/// - Warning: This property trades safety for performance. Use
/// `unsafelyUnwrapped` only when you are confident that this instance
/// will never be equal to `nil` and only after you've tried using the
/// postfix `!` operator.
@inlinable public var unsafelyUnwrapped: Wrapped { get }
它是一個定義的get方法,Optionl通過unsafelyUnwrapped
來獲取實際的值,例如:
var ddb: String? = "冬冬吧"
let ddbCount = ddb.unsafelyUnwrapped.count
這樣就得到了變量的實際值。
Optional的使用
實現一個Optional
let ddb: Optional<String> = "冬冬吧"
// var ddb: String? = "冬冬吧"
我們這樣實現的可選項,實際上和注釋部分的類型后面加?
實現的是完全一樣的。
可選項的解包
可選項是不能直接使用的,需要解包后才能使用,基本上有一下解包方式
-
!
強制解包,例如:
let count = ddb!.count
在強制解包前,你如果不知道它是否為nil
,那你需要先對它進行非nil的判斷保護,否則強制解包一旦失敗,程序會報錯,如下代碼:
if ddb != nil {
let count = ddb!.count
print(count)
}
這樣即使我們使用了強制解包,但它的運行依然是安全的
-
if
判斷展開,例如:
if ddb != nil {
let count = ddb?.count
print(count ?? 0)
}
這里我們使用a ?? b
合并空值運算符的方式來解包,如果有值,則為count
,如果為nil
,則默認0
使用合并控制運算符有兩個條件:
1.表達式a
必須是可選類型
2.表達式b
必須和a
的處處類型相同
- 使用可選項綁定的方式
if let ddbStr = ddb {
let count = ddbStr.count
print(count)
}
使用可選項綁定來判斷可選項是否有值,如果有就賦值給臨時變量。同一個if
語句可以有多個可選項綁定,用, 分開即可
小結
Optional,是”不存在“或“空”概念的加強版本。而nil
則是“不存在”的基礎版本
在swift中引入optional
的目的,就是將"不存在"這個概念綁定到具體的類型上。optional.nil
指向的是值的“不存在”,同時表示:如有值只能是optional.some<T>
中的T類型,將所有類型的值空間進行了nil的擴展。