一、前言
Swift
相較於OC
是一門型別更加安全的語言,其中引入的Optional
型別便是為了增強取值可靠性的一種方式。然而在新舊語言的轉換過程中總是會踩到坑中,由於自己對於這個概念的理解還沒有到位,在最近一次的實踐中就遇到了由於Optional Binding
引發的問題。
二、問題場景
textFiled
中的text
屬性是一個可選(optional
)型別,在對輸入狀態進行處理的時候肯定會涉及到對輸入內容的邏輯操作。在OC
中這種操作還是很直接的,直接使用.
語法(textField.text
)獲取屬性進行判斷。
但在swift
中text
是一個可選屬性,直接對屬性進行操作就比較冗餘了。因此我們往往會寫出如下的程式碼。
if var text = textField.text {
/// 邏輯操作
}
複製程式碼
這是swift中推薦的可選繫結的寫法,在其中的邏輯操作中text
就是textField.text
解包出的值,因此可以通過判斷text
的狀態,獲知textField.text
的狀態。
那麼問題來了,當我們判斷完成需要對textField.text
進行賦值的時候,一不小心就有可能直接寫出這樣的程式碼。
if var text = textField.text 【
/// 邏輯操作
text = "XXXXXXX"
}
print(textField.text!)
複製程式碼
列印textField.text
就會發現並不是text
賦值的值。
三、問題分析
一開始遇到問題我以為我是對Optional Binding
的理解有一些問題,檢視了蘋果的官方文件
You use optional binding to find out whether an optional contains a value, and if so, to make that value available as a temporary constant or variable.
使用可選繫結去確認一個可選型別是存在值的,進而可以將這個值作為一個臨時的常量或者變數。
文件上這個temporary
讓我以為是作用域的問題,然而情況並不是這樣。我專門宣告瞭一個textField?
型別的變數。
var testTextField: UITextField?
複製程式碼
接著建立一個textfield
let textField = UITextField(frame: CGRect(x: 100, y: 100, width: 100, height: 50))
textField.text = "測試資料"
testTextField = textField
複製程式碼
通過可選繫結獲取解包之後的testTextField
if let testTextField = testTextField {
testTextField.text = "測試資料1"
}
print(testTextField!.text!)
複製程式碼
此處的列印結果應該是什麼呢?--測試資料1
。
結果表明我們對可選繫結後的變數賦值是成功的,那麼問題又來了為何之前text
賦值不成功呢?
既然有成功的案例自然就證明了這個鍋並不該由Optional Binding
來背。
所以問題到底是出在哪裡呢?
仔細看兩次可選繫結的型別,一個使用了let
一個使用了var
,是因為這個原因麼?明顯不是,兩次可選繫結的物件型別一個是UITextField?
,另一個是String?
看出問題了麼?
UITextField
是引用型別,可選繫結的結果是指標,指向的記憶體是同一塊記憶體地址。String
是值型別,可選繫結的是具體的值,相當於新建了一個變數賦的值和textField.text
一樣而已。
四、總結
Swift
的設計理念就是儘可能拋棄一些歷史上存在的包袱,是一門更加高階和現代化的語言。而OC
身上就明顯刻印著C
的烙印,像NSString *
和UITextField *
,其中*
號就能讓開發者一目瞭然這是一個引用型別,Swift
中的引用型別和值型別並沒有符號來區分,因此在使用的過程中一定要更加謹慎才行。