為了解決空引用的問(wèn)題,Swift使用Optionals解決方案。
1.處理丟失的數(shù)據(jù)
我們使用Int類(lèi)型的age屬性來(lái)保存用戶(hù)的年齡,但有時(shí)候我們不知道用戶(hù)的年齡,該怎么辦?
存儲(chǔ)為0,或者-1表示未知,這兩個(gè)數(shù)字都是不太可能的。
Swift的解決方案是Optionals,使類(lèi)型變?yōu)榭蛇x。
var age: Int? = nil
age = 38
如果我們知道年齡,可以使用它。
為什么Swift有可選類(lèi)型?
在Swift中任何數(shù)據(jù)類(lèi)型都可以是可選的。
2.解包 if let
展開(kāi)可選內(nèi)容的一種常見(jiàn)方法是使用if let語(yǔ)法
if let unwrapped = name {
print("\(unwrapped.count) letters")
} else {
print("Missing name.")
}
可選值最重要的功能之一,Swift不允許我們?cè)诓幌日归_(kāi)它們的情況下使用它們。
這為我們所有的應(yīng)用程序提供了極大的保護(hù),因?yàn)樗柚沽瞬淮_定性:當(dāng)您處理一個(gè)字符串時(shí),您知道它是有效的字符串,當(dāng)您調(diào)用一個(gè)返回整數(shù)的函數(shù)時(shí),就可以立即安全地進(jìn)行操作。而且,當(dāng)您的代碼中確實(shí)包含可選內(nèi)容時(shí),Swift會(huì)始終確保正確處理它們-您檢查并解開(kāi)它們,而不僅僅是將不安全的值與已知的安全數(shù)據(jù)混合。
3.guard let
func greet(_ name: String?) {
guard let unwrapped = name else {
print("You didn't provide a name!")
return
}
print("Hello, \(unwrapped)!")
}
使用guard let, 可以在功能開(kāi)始前處理問(wèn)題,然后立即退出。意味著函數(shù)的其余部分是正確的,代碼將采用。
使用guard let 還是 if let?
guard在方法開(kāi)始時(shí),會(huì)使用一次或多次,它用于驗(yàn)證條件是否正確。如果想拆開(kāi)可選類(lèi)型,請(qǐng)使用if let ,如果想檢查條件,可以使用guard let。
4.強(qiáng)制解包
當(dāng)你可以確定值不是nil時(shí),你可以將可選類(lèi)型轉(zhuǎn)為非可選類(lèi)型。
let str = "5"
let num = Int(str)!
這時(shí)是確定不為空的,但如果你錯(cuò)了,代碼將崩潰。
因此只有確定它是安全時(shí),才可以使用強(qiáng)制解包。
什么時(shí)候采用強(qiáng)制解包?
即使您99.999%確信它是安全的,也不應(yīng)使用它
5.隱式解包
與常規(guī)的可選類(lèi)型不同,使用時(shí)你不需要解包。
let age: Int! = nil
使用它們不需要 if let 或 guard let
當(dāng)它們沒(méi)有值時(shí),使用它代碼會(huì)崩潰。
使用隱式解包主要是UIKit框架中使用,布局中不會(huì)立即創(chuàng)建控件,延遲到用戶(hù)顯示時(shí)。
而在SwiftUI中,這樣的方式已經(jīng)消失了,隱式解包不再重要。
6.nil合并運(yùn)算符
解包可選值,如果有則返回內(nèi)部值,如果沒(méi)有值,則使用默認(rèn)值。
let user = username(for: 15) ?? "Anonymous"
7.可選鏈
let surnameLetter = names["Vincent"]?.first?.uppercased() ?? "?"
8.try?
do try catch
enum PasswordError: Error {
case obvious
}
func checkPassword(_ password: String) throws -> Bool {
if password == "password" {
throw PasswordError.obvious
}
return true
}
do {
try checkPassword("password")
print("That password is good!")
} catch {
print("You can't use that password.")
}
使用try?來(lái)代替try
if let result = try? checkPassword("password") {
print("Result was \(result)")
} else {
print("D'oh.")
}
使用try!
如果可以確保函數(shù)不會(huì)失敗可以使用try!
try! checkPassword("sekrit")
print("OK!")
什么時(shí)候使用try?
如果只關(guān)注函數(shù)成功或失敗,使用try?是很好的選擇。
9.init?()
struct Person {
var id: String
init?(id: String) {
if id.count == 9 {
self.id = id
} else {
return nil
}
}
}
初始化方法失敗時(shí),對(duì)象創(chuàng)建失敗。你也可以將驗(yàn)證放到一個(gè)單獨(dú)的方法中,但是你很可能忘記調(diào)用它,放入初始化程序中安全的多。
10. as?
當(dāng)你知道某些對(duì)象的類(lèi)型時(shí),你可以對(duì)其進(jìn)行類(lèi)型轉(zhuǎn)換,使用as?,轉(zhuǎn)換失敗時(shí)返回nil。
let pets = [Fish(), Dog(), Fish(), Dog()]
for pet in pets {
if let dog = pet as? Dog {
dog.makeNoise()
}
}
11.總結(jié)
1.可選類(lèi)型使我們以清晰明確的方式表示值的缺失。
2.Swift不允許我們使用未解包的可選類(lèi)型,你可以使用if let 或 guard let解包
3.你可以強(qiáng)制解包,但是如果值為nil時(shí),會(huì)崩潰。
4.隱式解包類(lèi)型不會(huì)像可選類(lèi)型一樣檢查安全。
5.nil合并運(yùn)算來(lái)解包可選值,沒(méi)有則使用默認(rèn)值。
6.可選鏈?zhǔn)刮覀兛梢跃帉?xiě)代碼操作可選類(lèi)型,如果結(jié)果為空,代碼忽略。
7.使用try?會(huì)將throwing函數(shù)轉(zhuǎn)換為可選的返回值。或者使用try!,注意崩潰。
8.如果在初始化時(shí)加入錯(cuò)誤檢查,可以使用init?()。
9.使用類(lèi)型轉(zhuǎn)換將一種類(lèi)型轉(zhuǎn)換為另一種類(lèi)型。