Swift-Optional Binding引發的值型別與引用型別的思考

Doliant發表於2019-05-02

一、前言

Swift相較於OC是一門型別更加安全的語言,其中引入的Optional型別便是為了增強取值可靠性的一種方式。然而在新舊語言的轉換過程中總是會踩到坑中,由於自己對於這個概念的理解還沒有到位,在最近一次的實踐中就遇到了由於Optional Binding引發的問題。

二、問題場景

textFiled中的text屬性是一個可選(optional)型別,在對輸入狀態進行處理的時候肯定會涉及到對輸入內容的邏輯操作。在OC中這種操作還是很直接的,直接使用.語法(textField.text)獲取屬性進行判斷。 但在swifttext是一個可選屬性,直接對屬性進行操作就比較冗餘了。因此我們往往會寫出如下的程式碼。

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中的引用型別和值型別並沒有符號來區分,因此在使用的過程中一定要更加謹慎才行。

相關文章