從 可選型 到 Swift

可選型 就像是 薛定諤的貓


前言

作為一個(gè)Swifter 的初學(xué)者瞬欧,弄清楚 <font color=red>可選型(Optional)</font> 至關(guān)重要

我們來看一下 官方對 Optional 的定義:

A type that represents either a wrapped value or nil, the absence of a value.

public enum Optional<Wrapped> : ExpressibleByNilLiteral {

    case none
    
    /// The presence of a value, stored as `Wrapped`.
    /// 以包裝形式存在的值
    case some(Wrapped)
    ...
}

也就是說 Optional 是 一種含有2個(gè)類型的枚舉,它要么為空鳍烁,要么有值

有值: var statusCode: Int? = 404

空值: var errorCode: Int? = nil 
等價(jià)于 
var errorCode: Int? (默認(rèn)可選型 值為nil)

?

類比

當(dāng)我們在代碼里聲明一個(gè)可選型的類型時(shí),用 敬扛? 來執(zhí)行

let number: Int? = 10 // number 此時(shí)就是可選型

當(dāng)我們想要用到 number 這個(gè)值的時(shí)候晰洒,我們?nèi)ピ囍蛴∷玫?: Optional(10)

當(dāng)我們用 number 去與同類型的值相加時(shí) let a = number + 10,此時(shí)就會(huì)得到一個(gè)編譯時(shí)的錯(cuò)誤
也就是說,可選型 Optional(10) 不能直接參與運(yùn)算舔哪。

?

強(qiáng)制解包 !

在 可選型 的后面通過增加! 的形式, 解開被欢顷?包裝的類型 number

let a = number! + 10 

# 得到a 的類型是 Int槽棍,而不是Int捉蚤?,就代表此時(shí)a 類型明確 是Int

那么反觀 number ,當(dāng)我們打印的時(shí)候發(fā)現(xiàn)炼七,number 還是 Optional(10)

# 意味著 強(qiáng)制解包 并不會(huì)影響 原來被包裝的類型

如果 let number: Int? = nil 的話缆巧,則強(qiáng)制解包 number! 會(huì)崩潰

?

我們來類比一下薛定諤的貓

一只貓?jiān)谙渥永铮嬖谥环N既死又活的狀態(tài)豌拙,直到打開的時(shí)候我們才知道結(jié)果

薛定諤的貓 可選型 let number: Int? = 10
包裝值的類型 Int?
箱子 包裝值存放的盒子 Int? 存放的地方
陕悬? 套貓的繩子
按傅! 開盒子的鑰匙 捉超!

?

在這里, 我們把 死活狀態(tài) 類比為貓的 存在與否

? 比作套索 唯绍,我們用套索去盒子里圈喵星人的時(shí)候拼岳,我們并不知道盒子里有沒有喵星人

! 比作開盒子的鑰匙,開不開就看你控不控制的住了

?

擼er 們 况芒,不斬?zé)o名之輩惜纸,不開無貓之門

但實(shí)際上,沒打開盒子的時(shí)候绝骚,最多存在著2種情況

1. Int? 的值為 nil   喵星人不在    

2. Int? 的值為 10    喵星人活蹦亂跳耐版,ok 擼它 

我們不能貿(mào)然的用鑰匙去開門

你擼貓的動(dòng)作都準(zhǔn)備好了

發(fā)現(xiàn)沒有貓, 你難不難受?

你能想象你在輸入 一大串密碼后 查看開你的銀行卡余額
發(fā)現(xiàn)一毛沒有

你會(huì)怎么樣?

你會(huì)崩潰啊压汪,系統(tǒng)也會(huì)崩潰啊

但如果當(dāng)我們確定有喵星人的時(shí)候粪牲,我們是可以開門把喵星人揪出來的,

雖然我們把貓從盒子里拿出來了止剖,但是盒子又恢復(fù)了初始狀態(tài),里面還是有2種可能

結(jié)論:

1.當(dāng)我們 不確定可選型 有沒有值 的時(shí)候虑瀑,最好是不要去 強(qiáng)制解包
2.可選型有值,用 ! 去取值滴须,反之不取
3.強(qiáng)制解包 并不影響 被解包的類型舌狗,依舊還是可選類型

?

可選綁定 if let

解包除了強(qiáng)制解包這種粗魯?shù)男袨橥猓€有可選綁定

if let value = someOptional { 
    // do next 
    // 就是說如果 someOptional 有值扔水,才會(huì)進(jìn) if 循環(huán)
    // value 是 someOptional強(qiáng)制解包后的值痛侍,類型是確定的
    // value 的作用域 僅限于 {} 內(nèi)
    // 可以是 if let /  if var 
} 


舉個(gè)例子:

let number = Int("777") 

// 這里Int("777") 也是Int 類型 初始化的一種
// 返回的是一個(gè)可選型
// 因?yàn)槿绻麄髯址?"zzz" 就無法轉(zhuǎn)為Int,結(jié)果是不確定的

if let a = number {
    print("轉(zhuǎn)Int 成功",a) // 此時(shí)的a 是 number 解包后的值 777,而不是 Optional(777)
} else {
    print("轉(zhuǎn)Int 失敗 ")
}


* 如果有多個(gè)條件的可選值需要共同成立主届,比如

if let a = Int("1"),
   let b = Int("2") {
    print(a + b)
}
// 省略一個(gè)if 赵哲,中間以 逗號 拼接

if let 配合 while 使用

// 計(jì)算數(shù)組內(nèi) 為正數(shù)的值 的總數(shù)

var array = ["10","10","-10","a"]
var index = 0
var sum = 0
while let s1 = Int(array[index]),s1 > 0 {
    sum += s1
    index += 1
}
print(sum)

?

guard let

如果說 if let走到最后,那么 guard let 就代表著 <font color=red>提前退出</font>

guard 相比 if 來說君丁,用起來更加舒服

guard let value = someOptional else { 
    // value 沒有值枫夺,才會(huì)進(jìn) else 
    // value 的作用域 不限于{}
    // 可以是 guard let /  guard var 
    // must do return  
    // guard 必須要返回 退出 當(dāng)前作用域
}
print(value) // 這里的value 是 someOptional 解包后的值


舉個(gè)例子:

let number = Int("777") 

guard let num1 = number else {   
    print("轉(zhuǎn)換失敗")
    return
}

print(num1 + 10) 
// 能來到這里就說明  num1 是有值的,類型是確定的
// 打印 787

guard 相較于 if

  1. 層次比較分明
  2. 變量作用域更加廣泛
  3. 提前退出绘闷,效率更高

?

空合并 運(yùn)算符 ??

系統(tǒng)的定義是這樣的:

func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T?) rethrows -> T?

舉個(gè)例子:

表達(dá)式 a ?? b // 它意味著:如果a 不為空橡庞,返回a,否則返回b

  • 這里有一些注意點(diǎn):

1. a 必須是可選型印蔗,從定義中可以看到第一個(gè)參數(shù).. optional: T? , 就證明了a 必須是可選型

2. a 和 b 的類型 除了nil 這個(gè)類型以外扒最,另外一個(gè)類型必須是一致的

比如:
let a: Int? = 10
let b: Int? = 20
let c = a ?? b 

// c = Optional(10)
// a 和 b 都是可選型,另外一個(gè)類型都是 Int

3.b 可以是可選型,也可以不是

比如:
let a: Int? = 10
let b: Int = 20 
let c = a ?? b 

// c = 10

4.如果a 不為nil华嘹,返回a吧趣,此時(shí)系統(tǒng)并不會(huì) 牽扯到 b,b是多余的.

# 這里我們 注意 defaultValue: @autoclosure () 第二個(gè)參數(shù) 是帶有自動(dòng)閉包的
# 自動(dòng)閉包讓你能夠延遲求值耙厚,因?yàn)橹钡侥阏{(diào)用這個(gè)閉包强挫,代碼段才會(huì)被執(zhí)行

5.如果a 不為nil ,但b 不是可選型薛躬,返回a 的時(shí)候 a會(huì)自動(dòng)解包

什么意思呢俯渤?比如 

let a: Int? = 10
let b: Int = 20
let c = a ?? b

// a 是可選值 不為nil ,b 是 Int泛豪,非可選型
// 此時(shí)c = a! ,因?yàn)??? 后面的 b不是可選型,所以c 自動(dòng)解包
  • 結(jié)論

其實(shí)從官方定義可以看出稠诲,.... T?) rethrows -> T?

?? 的結(jié)果返回什么類型,取決于 參數(shù) b 的類型
?

隱式解包

有時(shí)候诡曙,在特定的情況下臀叙,一個(gè) Optional 可以被確保永遠(yuǎn)都有值 (或者說理應(yīng)永遠(yuǎn)都有值)

這時(shí)候每次使用都進(jìn)行判空和解包,就顯得很多余

在 可選型 初始化的時(shí)候 后面直接加 !价卤,在編譯的時(shí)候就 讓其自動(dòng)解包

你會(huì)覺得這 提莫 不就是 另一種形式 的強(qiáng)制解包嗎劝萤?

強(qiáng)制解包可選型

var aString: String? = "ttt"
aString! // 強(qiáng)制解包 "ttt"

隱式解包可選型

var aString: String! = "ttt" // 隱式解包

* 依舊可以置nil,因?yàn)閍String 依舊是可選型
aString! // 強(qiáng)制解包 "ttt"
aString  // Optional("ttt")
aString = nil 

* 如果將aString 賦值給bString慎璧,則 bString不需要解包了
let bString: String = aString  
bString = "ttt"
那么問題來了

1.如果我知道盒子里有喵星人床嫌,我還用套索 費(fèi)勁的 去抓它嗎?換言之 我還需要用可選型修飾嗎胸私?
2.為什么不直接用鑰匙打開盒子的門呢厌处?為什么不直接定義為String類型呢?
3.我如果確定它一直有值岁疼,從某種意義上說阔涉,那它不就丟失了可選型的初衷嗎?

我的理解,不知道對不對瑰排,還請指正

xib 中的控件我們都應(yīng)該清楚贯要,當(dāng)我們拖拽出一個(gè)button 的時(shí)候 ,會(huì)發(fā)現(xiàn):

@IBOutlet weak var btn: UIButton!
這個(gè)btn 就是 隱式解包椭住,對吧崇渗,就是說用到這個(gè)btn 的時(shí)候,自動(dòng)解包拿到btn

  • 這個(gè)地方為什么要隱式解包呢京郑?我認(rèn)為:

    • 每個(gè)屬性初始化的時(shí)候都是要有值的宅广,或者是可選的,或者隱式解包的
    • 拖拽出來的btn 在 awakeFormNib 初始化結(jié)束之后 才會(huì)被設(shè)置屬性
    • 初始化之后 大概率是要用的吧傻挂,不然也不會(huì)去拖線
    • 也就是說btn 肯定是會(huì)存在的乘碑,但是要在初始化之后挖息,除非你把連的線砍了
  • 那為什么不用 ?修飾呢

    • 大概率是因?yàn)橛媒鹁埽棵看味家?強(qiáng)制解包很麻煩,所以這里的屬性用!

結(jié)論:

隱式解包不是最安全的做法套腹,慎用

參考:When Should You Use Implicitly Unwrapped Optionals

?

字符串插值

image

有時(shí)候我們在打印一個(gè)字符串的時(shí)候绪抛,有可選型的插值,則會(huì)給出警告

var age: Int? = 10

# 三個(gè)fix 對應(yīng)下面3中解決方法

print("zzz is \(age!)") // 強(qiáng)制解包

print("zzz is \(String(describing: age))") // String 初始化

print("zzz is \(age ?? 20)") // 空合并給默認(rèn)值

?

后續(xù)有新的繼續(xù)補(bǔ)充...

個(gè)人筆記 有問題請多多指教

thanks for reading

....

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末电禀,一起剝皮案震驚了整個(gè)濱河市幢码,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌尖飞,老刑警劉巖症副,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異政基,居然都是意外死亡贞铣,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進(jìn)店門沮明,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辕坝,“玉大人,你說我怎么就攤上這事荐健〗闯” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵江场,是天一觀的道長纺酸。 經(jīng)常有香客問我,道長址否,這世上最難降的妖魔是什么餐蔬? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上用含,老公的妹妹穿的比我還像新娘矮慕。我一直安慰自己,他們只是感情好啄骇,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布痴鳄。 她就那樣靜靜地躺著,像睡著了一般缸夹。 火紅的嫁衣襯著肌膚如雪痪寻。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天虽惭,我揣著相機(jī)與錄音橡类,去河邊找鬼。 笑死芽唇,一個(gè)胖子當(dāng)著我的面吹牛顾画,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播匆笤,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼研侣,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了炮捧?” 一聲冷哼從身側(cè)響起庶诡,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎咆课,沒想到半個(gè)月后末誓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡书蚪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年喇澡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片善炫。...
    茶點(diǎn)故事閱讀 40,115評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡撩幽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出箩艺,到底是詐尸還是另有隱情窜醉,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布艺谆,位于F島的核電站榨惰,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏静汤。R本人自食惡果不足惜琅催,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一居凶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧藤抡,春花似錦侠碧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至瓷式,卻和暖如春替饿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背贸典。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工视卢, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人廊驼。 一個(gè)月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓据过,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蔬充。 傳聞我的和親對象是個(gè)殘疾皇子蝶俱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內(nèi)容