Swift學習心得 – Optional與Unwrap
「?」和「!」這兩個符號經常會在Swift程式中看到,它們算是Swift程式中比較特別的部份,我在本文中特別提出來,因為Optional型別在Swift中扮演了相當重要的角色,若不瞭解這兩個特殊符號的用法,便無法深入瞭解Swift。
在C語言,我們經常指定一個變數但沒有先給值,就像這樣:
如果我們一直都沒有給予它任何值,那麼在程式中使用到number這個變數時,我們便會得到undefined的錯誤訊息,此時,我們事後透過偵錯作業來更正這個錯誤。
而Swift則嚴格要求所有變數和常數都要先給值,不能為空值或unknow的值,但有時候,我們還是會有需要有空值的情況,例如,搜尋時傳回空的結果代表沒有找到任何資訊,因此,Swift為了解決這種狀況,建立了一種稱為「optional」的資料型別,凡是特別被指定為optional資料型別,代表它容許有值或沒有值,其它非optional型別的變數(預設狀況),則要求一定要有值。
沒有指定Optional會出現什麼問題?
舉例來說,上面程式的第一行沒有問題,但是到了第二行便會出現錯誤,為什麼?我們不是已經指定了空值(nil)給message變數了嗎?
這是因為若沒有指定的話,Swift變數預設都是non-optional而非optional型別,因此nil空值是不被接受的,我想Swift的考量點,主要是空值在程式運算中經常會造成問題,而Apple在創建Swift語言時又強調安全為首要考量,它不希望在Run time執行時期發生任何的錯誤,因此才會要求我們要預先告知那些可能為空值的變數,以避免後續可能造成的問題和debug,所以在上面範例中,我們的message必須被指定為optional才能將nil賦予給它。
所以同樣的,下方的範例也會在第二行出現compile錯誤,因為只有宣告而沒有指定值給message2,這點對於用Object-C開發APP的人而言可能會相當不習慣,因為Object-C的變數宣告時不需要給予啟始值。
指定optional型別
因此,要避免上述的錯誤,我們必須替那些可能沒有值的變數或參數加上「?」,表示它是optional,這樣Swift在compile時便可過關了,不會發生錯誤:
為什麼Swift要這麼特別的要求呢?這是有理由的,我們看看下方的Object-C例子:
這個findStockCode函式會傳回Apple或Google的美股代號,如果不是這兩個代號其中之一,那麼就會傳回nil空值。現在,我們在下方的程式碼中使用這個函式,執行結果會在紅色那行中發生runtime exception,因為傳入的是”Facebook”而不是Apple或Google,所以會讓函式傳回nil空值。
如果這個函式用Swift來寫,程式碼要修改如下:
請注意第一行,我們必須替傳回值型別String加入「?」符號,代表它為Optional,可能有傳回值,也有可能傳回nil(空值)。
這樣要求開發人員需特別的指定Optional便是為了避免意料外的情況(出現runtime error),以減少APP在執行時期可能產生的錯誤。(說明白了,也可能是為了APP的使用者體驗吧),也提昇了Swift程式碼品質。
Unwrap拆解
繼續前面的findStockCode函式範例,現在我們在Swift程式中要使用它:
結果卻還是在紅色那行產生了compile error,我們不是已經指定了Optional型別了嗎?為什麼還會發生錯誤?
這是因為在使用Optional型別變數時,我們必須先確定該Optional型別變數是否有值,若有的話必須用「!」來unwrap它才行,處理Optional有下列兩種方式:
接收和處理Optional型別
Forced Unwrapping
第一種是forced unwrapping,我們將上面的範例修改如下,執行時就不會出現錯誤了。請注意紅字的部份,我們加上了「if」和「! 」:首先使用if確定stockCode有值(有值會傳回true),然後再用「! 」來unwrap這個optional的變數。
如果我們沒有先用if 去判斷而直接去unwrap會有什麼結果?在complile時不會有任何錯誤,但是在執行時Swift會丟出如下的Runtime error,因此,先用if來判斷optional變數是必要的。
fatal error: Can’t unwrap Optional.None
Optional Binding
另一種較簡便且更常被使用的方式稱為optional binding,它可以快速的檢杳Optional變數是否有值,若有的話就unwrap它。我們一樣用上面的例子來說明:
紅色的部份「if let」是optional binding的重點,if let tempStockCode = stockCode這句話所作的事情就是:如果stockCode變數有值,就unwrap它並且把值放入tempStockCode這個暫存變數中,因為tempStockCode確定有值,所以我們不需要加上「!」的unwrap符號。
我們也可以將「if let」改成「if var」,省略tempStockCode這暫存變數,讓程式碼更為精簡:
以上是Optional和Unwrap的作法,在下一篇知識文件中,我們再來看看「Optional Chaining」可選鏈的用法,「Optional Chaining」指的是把呼叫、使用optional等等行為串連在一起,當其中有一段回傳nil,則整體的結果就是nil。
您好!現在閱讀文章,有圖例無法顯示的問題。
回覆刪除