Swift裏面的類型分為兩種:
●值類型(Value Types):每個實例都保留了壹分獨有的數據拷貝,壹般以結構體 (struct)、枚舉(enum) 或者元組(tuple)的形式出現。
●引用類型(Reference Type):每個實例***享同壹份數據來源,壹般以類(class)的形式出現。
在這篇博文裏面,我們會介紹兩種類型各自的優點,以及應該怎麽選擇使用。
值類型與引用類型的區別
值類型和引用類型最基本的分別在復制之後的結果。當壹個值類型被復制的時候,相當於創造了壹個完全獨立的實例,這個實例保有屬於自己的獨有數據,數據不會受到其他實例的數據變化影響:
代碼如下:
// 下面是壹個值類型的例子
struct S { var data: Int = -1 }
var a = S()
var b = a // b是a的拷貝
a.data = 42 // 更改a的數據,b的不受影響
println("(a.data), (b.data)") // 輸出結果 "42, -1"
值類型就好像身份證復印件壹樣,復印出來之後,修改原件上面的內容,復印件上的內容不會變。
另壹方面,復制壹個引用類型的時候,實際上是默默地創造了壹個***享的實例分身,兩者是***用壹套數據。因此修改其中任何壹個實例的數據,也會影響到另外那個。
代碼如下:
// 下面是壹個引用類型的例子
class C { var data: Int = -1 }
var x = C()
var y = x // y是x的拷貝
x.data = 42 // 更改x的數據,等於同時修改了y
println("(x.data), (y.data)") // 輸出結果 "42, 42"
Mutation(修改)在安全中扮演的角色
值類型較引用類型來說,會讓妳更容易在大量代碼中理清狀況。如果妳總是得到壹個獨立的拷貝出來的實例,妳就可以放心它不會被妳app裏面的其他部分代碼默默地修改。這在多線程的環境裏面是尤為重要的,因為另外壹個線程可能會在暗地裏修改妳的數據。因此可能會造成嚴重的程序錯誤,這在調試過程中非常難以排除。
由於差別主要在於修改數據的後果,那麽當實例的數據只讀,不存在需要更改的情況下,用哪種類型都是沒有分別的。
妳可能在想,有的時候我可能也需要壹個完全不變的類。這樣使用Cocoa NSObject對象的時候會比較容易,又可以保留值語義的好處。在今天,妳可以通過只使用不可變的存儲屬性,和避開任何可以修改狀態的API,用Swift寫出壹個不可變類(immutable class)。實際上,很多基本的Cocoa類,例如NSURL,都是設計成不可變類的。然而,Swift語言目前只強制struct和enum這種值類型的不可變性,對類這種引用類型則沒有。(例如還不支持強制將子類的限制為不可變類)
如何選擇類型?
所以當我們想要建立壹個新的類型的時候,怎麽決定用值類型還是引用類型呢?當妳使用Cocoa框架的時候,很多API都要通過NSObject的子類使用,所以這時候必須要用到引用類型class。在其他情況下,有下面幾個準則:
什麽時候該用值類型:
●要用==運算符來比較實例的數據時
●妳希望那個實例的拷貝能保持獨立的狀態時
●數據會被多個線程使用時
什麽時候該用引用類型(class):
●要用==運算符來比較實例身份的時候
●妳希望有創建壹個***享的、可變對象的時候
在Swift裏面,數組(Array)、字符串(String)、字典(Dictionary)都屬於值類型。它們就像C語言裏面簡單的int值,是壹個個獨立的數據個體。妳不需要花任何功夫來防範其他代碼在暗地裏修改它們。更重要的是,妳可以在線程之間安全的傳遞變量,而不需要特地去同步。在Swift高安全性的精神下,這個模式會幫助妳用Swift寫出更可控的代碼。