問號?
來定義一個可選項var name: String = "Jack"
name = nil
var age: Int?
age = 10
age = nil
複製代碼
C語言中,變量聲明以後,會自動被賦予初始值,Swift則不會這樣,可是Swift的Optional則會有默認的初始值nil
spring
func test() {
var age: Int -->沒有初始值,必須賦值以後才能使用
var weight: Double? --> 默認初始值爲nil, 等價於 var weight: Double? = nil
}
複製代碼
使用場景,有可能須要使用nil的地方swift
var array = [1,13,45,33]
func get(_ index: Int) -> Int? {
if index < 0 || index >= array.count {
return nil
}
return array[index]
}
print(get(1))// Optional(15)
print(get(-1))// nil
print(get(5)) // nil
複製代碼
nil
,那麼它是個空盒子nil
,那麼盒子裏裝的是:被包裝類型的數據var age: Int? // 默認就是nil
age = 10
age = nil
複製代碼
感嘆號!
進行強制解包var speed: Int? = 10
var speedInt: Int = speed!
speedInt += 10
複製代碼
nil
的可選項(空盒子)進行強制解包,將會產生運行時錯誤var age: Int?
age!
運行報錯:Fatal error: Unexpectedly found nil while unwrapping an Optional value: file Optional.xcplaygroundpage
複製代碼
let number = Int("123")
if number != nil {
print("字符串轉換整數成功:\(number!)")
} else {
print("字符串轉換整數失敗")
}
複製代碼
可選項綁定
來判斷選項是否包含值若是包含就自動解包,把值賦給一個臨時的常量(let
)或者變量(var
),並返回true
,不然返回false
api
if let number = Int("123") {
print("字符串轉換整數成功: \(number)")
-->number是強制解包以後的Int值
-->number的做用僅限於這個大括號
} else {
print("字符串轉換整數失敗")
}
複製代碼
用在枚舉值中數組
enum Season: Int {
case spring = 1, summer, autumn, winter
}
if let season = Season(rawValue: 6) { -->有可能獲得對應的case, 有可能得不到,那麼結果就爲空
switch season {
case .spring:
print("the season is spring")
default:
print("the season is other")
}
} else {
print("no such season")
}
複製代碼
注意下面的等價用法markdown
if let first = Int("4") {
if let second = Int("42") {
if first < second && second < 100 {
print("\(first) < \(second) < 100")
}
}
}
======等價寫法以下, 經過逗號來分割 帶可選項綁定的 if判斷條件
if let first = Int("4"),
let second = Int("42"),
first < second && second < 100 {
print("\(first) < \(second) < 100")
}
複製代碼
---->遍歷數組,將畫遇到的整數都加起來,若是遇到負數或者非數字,中止便利
var strs = ["10", "20", "abc", "-30", "30"]
var index = 0
var sum = 0
while let num = Int(strs[index]), num > 0 {
sum += num
index += 1
}
print(sum) // 30
複製代碼
public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T?) rethrows -> T?
public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T
複製代碼
a ?? b
app
a
必須是可選項b
是可選項 或者 不是可選項b
跟a
的存儲類型必須相同- 若是
a
不爲nil
,就返回a- 若是
a
爲nil
,就返回b- 若是
b
不是可選項,返回a
時回自動解包
let a: Int? = 1
let b: Int? = 2
let c = a ?? b //c是Int?, Optional(1)
複製代碼
let a: Int? = nil
let b: Int? = 2
let c = a ?? b //c是Int?, Optional(2)
複製代碼
let a: Int? = nil
let b: Int? = nil
let c = a ?? b //c是Int?, nil
複製代碼
let a: Int? = 1
let b: Int = 2
let c = a ?? b //c是Int, 1
複製代碼
let a: Int? = nil
let b: Int = 2
let c = a ?? b //c是Int, 2
複製代碼
若是沒有??
,有些代碼寫起來就比較麻煩ui
let a: Int? = nil
let b: Int = 2
let c: Int
if let tmp = a {
c = tmp
} else {
c = b
}
複製代碼
從左往右算this
let a: Int? = 1
let b: Int? = 2
let c = a ?? b ?? 3 //c是Int, 1
複製代碼
let a: Int? = nil
let b: Int? = 2
let c = a ?? b ?? 3 //c是Int, 1
複製代碼
let a: Int? = nil
let b: Int? = nil
let c = a ?? b ?? 3 //c是Int, 1
複製代碼
let a: Int? = nil
let b: Int? = 2
if let c = a ?? b {
print(c)
}
-->相似於 if a != nil || b != nil {}
複製代碼
if let c = a, let d = b {
print(c)
print(d)
}
-->相似於 if a != nil && b != nil {}
複製代碼
func login(_ info: [String : String]) {
let username: String
if let tmp = info["username"] {
username = tmp
} else {
print("請輸入用戶名")
return
}
let password: String
if let tmp = info["password"] {
password = tmp
} else {
print("請輸入密碼")
return
}
print("用戶名:\(username)","密碼:\(password)", "登陸ing")
}
login(["username": "jack", "password": "123456"])
login(["password": "123456"])
login(["username": "jack"])
************運行結果
用戶名:jack 密碼:123456 登陸ing
請輸入用戶名
請輸入密碼
複製代碼
上面的登陸業務經過guard
來實現spa
func login(_ info: [String : String]) {
guard let username = info["username"] else {
print("請輸入用戶名")
return
}
guard let password = info["password"] else {
print("請輸入密碼")
return
}
print("用戶名:\(username)","密碼:\(password)", "登陸ing")
}
login(["username": "jack", "password": "123456"])
login(["password": "123456"])
login(["username": "jack"])
***********運行結果
用戶名:jack 密碼:123456 登陸ing
請輸入用戶名
請輸入密碼
複製代碼
感嘆號!
定義一個隱式解包的可選項let num1: Int! = 10 //若是能肯定某個變量會一直不爲nil,可使用這種聲明方式,
let num2: Int = num1 // 能夠直接使用,系統會自動解包後賦值,固然也可使用強制解包方式,可是num1的本質仍是一個optional
if num1 != nil {
print(num1 + 6)
}
if let num3 = num1 {
print(num3)
}
複製代碼
若是給隱式解包類型的optional
變量賦值nil
,當該變量被賦值給其餘變量/常量式,會出現 運行時報錯
debug
let num4: Int! = nil
let num5: Int = num4 -->注意,程序執行完這一句纔會報錯,在執行這一句的時候,會對num4進行隱式解包,結果發現它內部是nil,所以把nil取出來賦值給 num5: Int 的時候就報錯了,由於 num5 不能爲空
Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
複製代碼
上述的案例,讓人感受使用帶!的optional存在不少風險,其實用下面的方式莫不是更保險點嗎,
var num5: Int = 10
let num5: int = num56
複製代碼
這樣至少在程序運行以前,就能看到錯誤,若是有的話。
實際上,咱們大部分場景下,也都是推薦使用帶
?
的optional
,那用!
聲明的optional
存在的意義是什麼呢?
- 若是你提供一套api給外界使用,而且指望使用者嚴格遵照你的要求不要傳
nil
過來,而且認爲使用者在錯誤使用的時候而致使程序直接報錯崩潰就是你期待的,那麼你可使用這種用法。除此以外,仍是不用爲妙。
可選項在字符串插值或者直接打印的時候,編譯器會發出警告
var age: Int? = 10
print("My age is \(age)")//直接進行字符串插值,會產生編譯器警告
//️String interpolation produces a debug description for an optional value; did you mean to make this explicit?️
複製代碼
3種經常使用的方法能夠消除警告
var age: Int? = 10
print("My age is \(age!)")
print("My age is \(String(describing: age))")
print("My age is \(age ?? 0)")
複製代碼
var num1: Int? = 10
var num2: Int?? = num1
var num3: Int?? = 10
print(num2 == num3) // true
複製代碼
num1
、num2
、num3
的結構分別以下
再看以下
var num1: Int? = nil
var num2: Int?? = num1
var num3: Int?? = nil
print(num2 == num3) // false
(num2 ?? 1) ?? 2 //1
(num1 ?? 1) ?? 2 //2
複製代碼
可使用LLDB指令
frame variable -R
或者fr v -R
來查看變量的內部信息。
有關Swift的可選項就整理到這裏。