iOS新手入門 — 變數三部曲(3/3) — 俏皮的神秘箱 Optional

威爾哥(Will, Tsai)
蔡胖想學做生意
15 min readAug 4, 2018

諸君!

好久不見!

沒錯,我就是

人帥心善打字快, 寫code debug樣樣來 的 威爾哥!

歡迎來到威爾哥的iOS小教室。

相信各位在使用Swif進行開發的時候,常常發現某些變數的後面有個問號?或者驚嘆號!

為什麼呢?

莫非這個變數是個充滿疑問的,懸疑的變數!

抑或是代表這個變數是很容易吃驚的變數!

其實呢,有句話說,寫程式就像在寫作文,所以Swift工程師大量使用這些標點符號來表達他們心中那股慷慨激昂的心情。

時而疑惑,偶而迷茫。

有時低落沮喪,有時慷慨激揚。

是不是很有道理啊!!

嗚嗚…這年頭的年輕人都不能接受老人搞笑了嗎…

好吧,那讓我們進入正題!

本文主旨是介紹Swift中的Optional,

整篇文章將分為以下幾個部分進行。

  1. 為什麼要有Optional?了解空值的概念!
  2. 認識Optional
  3. 開箱囉,把數值從Optional拿出來
  4. 擺脫驚嘆號與問號吧!
  5. 所以到底為什麼要使用Optional ?
  6. 實作影片
  7. 結論

好,那麼威爾哥的iOS小教室,正式開始~~~~~~~

為什麼要有Optional?了解空值的概念!

在我們開始了解Optional之前,讓我們先了解一下Optional這個東西為什麼會被發明出來。

Optional被發明出來是為了表示『空值』這個概念。

那什麼是空值呢?

舉例來說

如果我們這個月很努力地上班,或許我們可以得到22K(嗚嗚)

但是如果當月沒上班,我們可能只能領到0元。

但是無論是22K或者是0元,這個數值都是一個值。

但是萬一某一個月,老闆沒發工資的話,

等我們回家的時候,老婆一問起,我們會說 沒薪水!老闆沒發!

沒發薪水就是代表空值!

因為我們根本沒有拿到薪水,所以薪水不是22K也不是0,而是空的!

或許有些小夥伴會想說用 負數 來代表空值這種狀態。

但是在某些例子上,負數並不是很恰當的解法。

讓我們再用薪水這個例子看看

如果今天我們的薪水是領到了 -100元!

這代表老闆沒發薪水嗎?感覺不是

這樣的表示法,反而比較像是 這個月白做工,然後還要倒貼給老闆100元。

所以說,我們需要有一個特殊的方法來表示『 空值 』這個狀態。

而在Swift中,我們使用Optional來表示這個變數有可能是空值。

🛎️ 小結:
1.空值就是『沒有值』。不是正數也不是負數,而是沒有值。
2.Swift使用Optional這種特殊的資料型態來表示『空值』這個概念,

認識Optional

了解了為什麼Optional被發明出來背後的原因之後,接下來讓我們來認識一下Swift中的Optional吧。

在Swift中,我們常常可以看到問號跟驚嘆號。

感覺用Swift寫APP的工程師感情都很豐富。

但是其實,這兩個符號在Swift中是另有用途的。

讓我們從問號開始講起吧!

我們知道,在Swift中,所有的變數都必須要經過初始化才能使用,也就是說每個變數都必須保證裡面有值。

變數沒初始化之前是不能使用的
給予初始值之後才能使用

但是Optional不一樣,他是一種特別的資料型別,它特別的地方在於,這個箱子是允許空值存在的。所以即使沒有給初始值也是可以正常使用。

宣告變數為Optional, 沒給定初始值也不會有錯誤訊息出現
此時fruit是空值,所以印出來看可以發現fruit的值是nil

簡單講,一般的變數就是普通的箱子,箱子裡面一定有裝東西。但是Optional不一樣,當收到Optional箱子的人打開的時候,裡面可能有東西,也可能沒東西。哇,簡直就是驚喜箱啊!

翻譯翻譯

如果在宣告變數的時候,我們在變數的資料型別後面加上一個問號。

那麼這個變數的資料型別將從原本的型別變成Optional型別。

所以被宣告為Optional的變數,其資料型別其實已經不是原本的資料型別,而是變成Optional型別,裡面包著原本我們宣告的資料型別。

舉例來說

宣告一個optional的變數,並且印出來
印出來的字串長這樣

上圖中,我們宣告了一個optional的變數,Optional裡面包著的是一個變數名稱為fruit 的String,然後儲存的值是Apple。

當我們把這個變數印出來的時候,

我們可以看到apple這個字串被包在Optional()裡面。

這代表這個變數已經被放入Optional這個箱子裡面了。

所以此時fruit變數的資料型別就變成 Optional,Optional箱子裡面可能裝著一個String,但是也可能沒有任何東西(nil).

接下來,可能有些同學會有疑問,就是當變數被宣告成Optional之後,除了變成允許空值之外還有什麼不一樣的地方嗎?

當然有!

因為資料型態已經從原本的資料型別被轉變成為Optional了,所以原本該資料型別可以執行的方法也通通噗嚕噗嚕的消失囉~

不believe?好吧,check it out.

讓我們再以上面的fruit變數當例子,

首先我們先在fruit中放數全部大寫的APPLE,然後呼叫字串的lowercased()這個方法把字串轉成全部小寫。

使用String的lowercased()方法可以得到全小寫的新字串

OK,順利完成了。

但是接下來,當我們把這個字串加上問號之後呢,

哎呀,XCode突然告訴我們,先生你這樣母湯喔。不能執行這個方法!

原本可以執行的程式現在跳出警告,不給執行啦

這是為什麼呢?

因為這時候的字串已經不是String型別,而是Optional型別裡面包著一個String。而Optioinal型別並沒有具備這個方法可以執行,所以xcode會跟我們說,不行,辦不到。

但是神奇的是,我們都知道變數只能儲存跟變數資料型別一樣的資料。

但是如果變數被宣告成Optional之後,資料型別也會被轉成Optional,那下面這段程式碼為什麼可以執行?

apple是字串,fruit是一個Optional型態然後Optional中包著String的變數,

資料型別不一樣,為什麼可以儲存這個值呢?

答案是,當我們要指定一個值給Optioinal變數的時候,XCode會很貼心的幫我們檢查Optional裡面包著的資料的型態,如果Optional裡面包著的資料型別跟我們要存放的資料的資料型別一樣的話就允許我們儲存。

相同的情形也發生在比較兩個值是否相同時候,例如下圖

得到的結果是兩個字串一樣

Xcode在我們執行比較的時候,會自動先把變數從Optional裡面拿出來,再接下去做比較。

所以我們不用擔心因為資料型別被轉為Optional而導致這種比較失敗。

好,學會了把變數放在optional裡,接下來我們就要來了解一下如何把變數拿出來啦。

🛎️ 小結:       1.被宣告為Optional的變數,原本的資料型別會變成Optional。

2.宣告為Optional的變數,允許存放『空值』。
3.被宣告為Optional之後,原本的資料型別可以執行的方法都不能執行了。 4.在將值塞到optional變數時候,XCode把Optional中包裹著的資料型別拿出來 比對,資料型別相同的才能存入 5.比較變數的值的時候,XCode會自動把值從Optional中拿出來做比對,不需要自己手動取值。

開箱囉,把數值從Optional拿出來

那麼我們要怎麼把數值從optional箱子中拿出來呢?

首先,拿出來的方法有兩種,

第一種方法叫做,我也不知道,不然試看看好了。又稱作Optional Chaining

第二種叫做,我在這邊斬雞頭發誓,箱子裡面保證一定有東西。也稱為Force unwarping。

由於第二種太激進,身為工程師的我們是從尚和平的,所以還是從第一個先看起吧

Optional Chaining…讓我先咪一咪

Optional Chaining

Optional Chaining很簡單,就是在我們使用變數的地方後面加上個問號?就可以了,如下圖所示

上圖中,fruit的後面多了一個問號。

這樣的寫法表示,我知道這個數值被包在Optional中,但是不知道有沒有箱子裡有沒有值,所以我先額外產生一個Optional箱子,然後試著把fruit裡面儲存的值拿出來放到額外產生的Optional箱子裡面。所以如果是用問號拿出來的話,如果有數值,那麼整串最後的回傳值會是一個Optional裡面包著我們想要的值。

如下圖,最後得到的是小寫的apple但是還是被包在Optional之中。

如果過程中任何一個參數為 nil ,則整串程式碼直接結束執行(後面沒執行的都直接跳過不執行),並傳回 nil 。

使用Optional Chaining的好處就是,我們的程式已經有心理準備箱子裡面沒東西,所以就算最後得到的是空值,程式也不會Crash。

Force unwrapping

第二種拿出來的方法叫做force unwrapping,

代表的意思就是我在這邊斬雞頭發誓,箱子裡面保證一定有東西。

Force unwrapping的寫法如下,在fruit的後面加上一個驚嘆號(!)即可。

但是因為我們的fruit是空值,所以在第四行的地方我們馬上就收到一個錯誤訊息。

如下圖

Fatal error:Unexpectedly found nil while unwrapping an Optional Value

這個訊息的意思就是,從optional拿東西出來的時候,以為有東西,結果沒東西,所以程式崩潰了。

擺脫驚嘆號與問號吧!

自從用了Optional之後,雖然我們的程式因為允許空值,所以得到了額外的彈性,但是相對的也帶來了一些新的困擾。

例如,如果使用Optional Chaining取值,則當不該是空值的地方變成空值的時候,程式不會崩潰,所以不容易除錯。

相反的,如果使用Force unwrapping,我們可以藉由程式崩潰得知有地方出錯了,所以比較容易除錯,

但是相對的,如果使用者使用我們的APP,三不五時就閃退,那麼我們的APP應該是難逃被刪除的命運。

最後,自從用了Optional之後,我們可以發現我們的程式碼到處充滿了問號跟驚嘆號,不知道的人經過看到還以為我們是在寫作文呢。

所以為了避免上面這些情況發生

在這邊我們可以使用下面幾種方法來解決

  1. 自動取值

自動取值,就是在我們宣告變數的時候,在資料型別後面加上!驚嘆號。

加上驚嘆號就表示,每次我們使用這個變數的時候,XCode會自動使用force unwarpping把數值從變數中取出來!所以在第四行的地方,我們可以直接使用fruit而不需要使用fruit?或者fruit!來取值。

雖然使用這個方法,可以省去我們每次都要用問號取值的麻煩,但是因為我們是拍胸脯保證Optional裡面一定有值,所以如果Optional裡面沒有東西的話,我們的APP就會直接閃退,閃起來。

  1. Optional Binding

Optional Binding的寫法如下圖的第四行。

Optional Binding就是在我們要使用該變數的時候,先宣告一個If判斷式,在這個判斷式中,我們把optional裡面的東西放在等號左邊的區域變數(unwrappedFruit)中。

如果unwrappedFruit不是nil的話,程式會執行If判斷式裡面的內容。然後在If判斷式中我們都可以使用unwrappedFruit這個區域變數代替fruit來進行運算。不需要每一次都使用fruit?或者fruit!。

  1. Guard

最後,我們可以使用Guard關鍵字來把值從Optional中拿出來,如下圖中第四行。

Guard這個關鍵字,後面接一個條件判斷式,如果條件成立,程式繼續往下執行,但是如果不成立的話,就執行else裡面的部分。

舉例來說,我們要替APP寫一個登入功能。

使用者執行登入的時候,必須輸入帳號以及密碼。

這種情境之下,我們就可以使用guard關鍵字來取值。

上圖第五行代表的意思是,如果login方法的參數 userAccount與userPassword都有值的話,我們把值拿出來,存到區域變數account以及password裡面。

接下來在guard條件式之後的程式碼都可以直接用account以及password進行登入,不需要再檢查有值或者無值。

但是如果沒有其中之一是空值的話,我們便執行else中的程式碼,印出訊息,然後執行return,結束登入功能的執行。

如何,484很方便啊!

🛎️ 小結:
取值的方法如下
1.Optional chaining - 使用問號取值,取得空值時程式不會Crash
2.Force unwrapping - 使用驚嘆號取值,取得空值時,程式Crash
3.Optional binging - 使用 if 條件式取值
4.使用 guard 條件式

所以到底為什麼要使用Optional ?

使用Optional,嚴格說來有兩個好處跟一個不得不的苦衷。

首先

不得不的苦衷就是

  1. 歷史共業,為了跟Objective-C介接!

在Swift出現之前,iOS整套系統都適用Objective-C來進行開發。當時Objective-c的世界中也有空值這個概念,並且使用nil這個值來代表。

後來當Swift出現之後,為了跟整套用Objective-c開發的iOS系統無縫接軌,所以Swift中設計了Optional這個機制來處理。

  1. 可以表示空值

就可以表示空值…

  1. 可以延後初始化的時間

有時候,我們的資料不是放在APP裡面,而是放在伺服器中。

所以當我們的用戶開啟APP的時候,APP必須先從SERVER上下載資料。

但是問題是從『開始下載資料』到『下載完成』,這段時間是不固定的。

因此我們的APP無法確定什麼時候才有資料可以顯示給使用者看。

但是沒資料的時候,我們的APP總不能直接死掉給使用者看吧。

這種『等一下才有東西可以展示』的情況就是使用Optional最好的時機了。

每當要顯示資料之前,我們的APP都可以先檢查一下資料是不是已經下載完成了,

如果還沒就做其他事情,如果已經完成了就顯示資料。

所以說Optional就是行!

🛎️小結:
這一段這麼短...就別結了吧....

實作影片

上面看了這麼多,是否還是有點模糊呢?

沒關係,讓我們來看一下實作的影片吧!

導播,上影片~~~~~~!

結論

Optional在Swift中是不可或缺的重要元素。透過使用Optional,我們可以很直覺地表示資料為空值的狀態。雖然一開始可能會被Optional弄的昏頭轉向,但是瞭解了Optional代表的意義以及運行的機制之後,相信大家一定可以感受到Optional的魅力所在!

好,那麼今天的Optional就説到這邊啦,希望各位看倌兒滿意!

正所謂,

持續關注威爾哥,學習iOS笑呵呵。

威爾哥的iOS小教室,我們下次見!

️千山萬水總是情,按個「拍手」行不行。如果你覺得我的文章還不錯,可以「Follow」我,然後順手按個拍手鼓勵鼓勵我!按住👏 1秒 ,神清氣爽。
按住👏 5秒 ,通體舒暢。
按住👏 10秒,說吧,要吃什麼,今晚宵夜我請。
謝謝大家!

--

--

威爾哥(Will, Tsai)
蔡胖想學做生意

作者自稱威爾哥,是個想養貓但是自己都需要人養,漂流在墨爾本的程式設計師,曾經碰過前端開發,後端開發,android開發,現在主要研究iOS開發,興趣是寫寫廢文跟大家分享。