對于使用Objective-C開發(fā)iOS的程序員來說,對象是否為nil在編寫程序的過程中程序員不太關(guān)心,直接使用就可以,在一些需要判斷的地方在判斷敛腌,當轉(zhuǎn)為Swift開發(fā)時,首先頭疼的問題就是可選類型,到底何時使用迎瞧?夸溶,何時使用!總是拿不太準凶硅,下面就詳細的講解一下
一缝裁、什么是可選類型
可選類型伴隨著Swift誕生,在原有的Objective-C語言中不存在足绅,究其原因捷绑,是因為Swift是類型安全的語言,而OC則是弱類型語言氢妈,OC中 str字符串既可以是nil粹污,也可以是字符串,而Swift中首量,這兩種狀態(tài)是不能同時存在的壮吩。
OC和Swift對于nil的解釋也是不太一樣的
1.Objective-C中的nil:表示缺少一個合法的對象,是指向不存在對象的指針加缘,對結(jié)構(gòu)體鸭叙、枚舉等類型不起作用(會返回NSNotFound)
2.Swift中的nil:表示任意類型的值缺失,是一個確定的值拣宏,要么是該類型的一個值要么什么都沒有(即為nil)
在Swift中Optional(可選類型)是一個含有兩種情況的枚舉沈贝,None 和 Some(T),用來表示可能有或可能沒有值勋乾。任何類型都可以明確聲明為(或者隱式轉(zhuǎn)換)可選類型宋下。當聲明一個可選類型的時候,要確保用括號給 ? 操作符一個合適的范圍辑莫。
1.1可選類型的聲明
var optionalStr: String? = "swift語言可選類型"http://聲明可選類型字符串学歧,并賦初值
var opStu:Student? //聲明可選opStu對象,賦初值nil
注意:在類型和 ?之間沒有空格
1.2 強制解析(拆包)
當你確定自定義的可選類型一定有值時各吨,可以使用操作符(!)進行強制解析枝笨,拿到數(shù)據(jù),嘆號表示"我知道一定有值绅你,請使用它",但是當你判斷錯誤,可選值為nil時使用(!)進行強制解析昭躺,會有運行錯誤忌锯。
var myStr:String? = nil
myStr="強制解析,一定有值"
if myStr != nil {
print(myStr!)//使用领炫!進行強制解析
}else{
print("字符串為nil")
}
運行結(jié)果
強制解析偶垮,一定有值
1.3 自動解析
在最初的聲明時使用?修飾,當你希望它自動解析是可以用似舵!代替脚猾?來修飾,這樣在變量使用時就不需要加砚哗!來強制拆包龙助,它會自動解析。
var myStr:String! //使用蛛芥!修飾
myStr="自動解析"
if myStr != nil {
print(myStr)
}else{
print("字符串為nil")
}
運行結(jié)果
自動解析
1.4 可選綁定
A.使用可選綁定提鸟,擺脫了頻繁的判斷是否為nil在賦值,但是使用可選綁定(optional binding)來判斷可選類型是否包含值仅淑,如果包含就把值賦給一個臨時常量或者變量称勋。可選綁定可以用在if和while語句中來對可選類型的值進行判斷并把值賦給一個常量或者變量涯竟。
格式:
if let tempStr = someOptional{
tempStr//如果someOptiona有值的話赡鲜,就會賦值給tempStr,然后使用
}
var myStr:String?
myStr="可選綁定"
if let tempStr = myStr {
print(tempStr)
}else{
print("字符串為nil")
}
運行結(jié)果
可選綁定
B.在可選類型判斷中還有g(shù)uard let的用法庐船,guard名為守衛(wèi)的意思银酬。guard let和if let剛好相反,guard let守護一定有值醉鳖。如果沒有捡硅,直接返回
let name: String? = "張三"
let age: Int? = 10
guard let nameNew = name,
let ageNew = age
else {
print("姓名 或 年齡 為nil")
return
}
print("姓名 或 年齡 為\(name),\(age)")//運行到這里是一定有值的
1.5 as! 與 as? 的類型轉(zhuǎn)換
在寫Swift代碼時總是拿不準到底使用哪個,有時會根據(jù)編輯器的提示去Fix盗棵,但是這樣不能很好的解決問題壮韭。
1.as!使用場合
向下轉(zhuǎn)型(Downcasting)時使用。由于是強制類型轉(zhuǎn)換纹因,如果轉(zhuǎn)換失敗會報 runtime 運行錯誤喷屋。就是說強制從父類轉(zhuǎn)換成子類
class Animal {}
class Cat: Animal {}
let animal :Animal = Cat()
let cat = animal as! Cat
2.as?使用場合
as? 和 as! 操作符的轉(zhuǎn)換規(guī)則完全一樣。但 as? 如果轉(zhuǎn)換不成功的時候便會返回一個 nil 對象瞭恰。成功的話返回可選類型值(optional)屯曹,需要我們拆包使用。由于 as? 在轉(zhuǎn)換失敗的時候也不會出現(xiàn)錯誤惊畏,所以對于如果能確保100%會成功的轉(zhuǎn)換則可使用 as!恶耽,否則使用 as?
let animal:Animal = Cat()
if let cat = animal as? Cat{
print("cat is not nil")
} else {
print("cat is nil")
}
二、可選類型的使用場景
2.1 函數(shù)或方法的返回類型為可選類型
在方法中返回值如Int?颜启、String?偷俭、(Int, String)?、[Int]?缰盏、[Int: String]?等
func returnOptionValue(value: Bool) -> String? { // 返回類型為可選String類型
if value {
return "返回類型是可選類型值" // 如果為真涌萤,返回Int類型的值1
} else {
return nil //返回nil
}
}
let optionValue = returnOptionValue(value: true) // 要用可選綁定判斷再使用淹遵,因為returnOptionValue為String?可選類型
if let value = optionValue {
print(value)
} else {
print("none value")
}
運行結(jié)果
返回類型是可選類型值
返回類型為閉包可選
func returnOptionalFunc(value: Bool) -> (() -> (Void))? { // 返回類型為可選類型的閉包
if value {
return { () in
print("返回類型是可選類型閉包")
}
} else {
return nil
}
}
let possibleFunc = returnOptionalFunc(value: true) // 要用可選綁定判斷再使用负溪,因為possibleFunc 為可選類型的閉包透揣,類型為() -> (Void)
if let aFunc = possibleFunc {
print(aFunc()) // 注意增加()調(diào)用閉包,因為沒有參數(shù)則是空括號
} else {
print("none func")
}
運行結(jié)果
返回類型是可選類型閉包
2.2 可選類型在類或結(jié)構(gòu)體中的運用
可選類型在類中的使用
class PossibleClass {
var someValue: Int
var possibleValue: String? // 可選存儲屬性川抡,默認值為nil
init(someValue: Int) { // 構(gòu)造方法中可以不對possibleValue屬性初始化
self.someValue = someValue
}
}
let someClass = PossibleClass(someValue: 4)
可選類型在結(jié)構(gòu)體中的運用
struct PossibleStruct {
var someValue: Int
var possibleValue: String? // 可選存儲屬性辐真,默認值為nil
// 結(jié)構(gòu)體中可以自定義一個init構(gòu)造器對屬性初始化,也可以不自定義
}
let someStruct = PossibleStruct(someValue: 4, possibleValue: nil)
2.3 可選類型在構(gòu)造器中使用
class PossibleStructInit {
let someValue: String
init?(someValue: String) { // 可失敗構(gòu)造器
if someValue.isEmpty { return nil } // 如果實例化為空串猖腕,則返回nil(即實例化失敗)
self.someValue = someValue
}
}
let oneStruct = PossibleStructInit(someValue: "構(gòu)造器中使用") // abc不是空串拆祈,oneStruct為PossibleStructInit?可選類型
if let one = oneStruct { // 使用if let可選綁定判斷
print(one.someValue)
} else {
print("none value")
}
//輸入結(jié)果為:構(gòu)造器中使用
let twoStruct = PossibleStructInit(someValue: "") // 傳參為空串
if let two = twoStruct {
print(two.someValue)
} else {
print("none value")
}
//輸入結(jié)果為:none value
2.4 可選類型在錯誤處理中使用(try!與try?)
1.try?會將錯誤轉(zhuǎn)換為可選值倘感,當調(diào)用try?+函數(shù)或方法語句時候放坏,如果函數(shù)或方法拋出錯誤,程序不會發(fā)崩潰老玛,而返回一個nil淤年,如果沒有拋出錯誤則返回可選值。
2.使用try!可以打破錯誤傳播鏈條蜡豹。錯誤拋出后傳播給它的調(diào)用者麸粮,這樣就形成了一個傳播鏈條,但有的時候確實不想讓錯誤傳播下去镜廉,可以使用try!語句
let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")
// 上述語句中在執(zhí)行l(wèi)oadImage方法時如果執(zhí)行失敗弄诲,使用try!來禁用錯誤傳遞,會有運行錯誤導致App崩潰
func someThrowingFunction() throws -> Int {
// ...
}
let x = try? someThrowingFunction() // x可能正常返回一個Int類型的值也有可能拋出一個錯誤異常娇唯,使用時對x用if let可選綁定判斷