Swift 里面的類型分為兩種:
- 值類型(Value Types):每個(gè)實(shí)例都保留了一分獨(dú)有的數(shù)據(jù)拷貝,一般以結(jié)構(gòu)體 (struct)、枚舉(enum) 或者 元組(tuple)的形式出現(xiàn)。
- 引用類型(Reference Type):每個(gè)實(shí)例共享同一份數(shù)據(jù)來源,一般以 類(class)的形式出現(xiàn)。
接下來我們來一一介紹一下他們的區(qū)別
1、存儲(chǔ)方式
值類型存儲(chǔ)在棧區(qū)。 每個(gè)值類型變量都有其自己的數(shù)據(jù)副本,并且對(duì)一個(gè)變量的操作不會(huì)影響另一個(gè)變量。
引用類型存儲(chǔ)在其他位置(堆區(qū)),我們?cè)趦?nèi)存中有一個(gè)指向該位置的引用。 引用類型的變量可以指向相同類型的數(shù)據(jù)。
2、值類型和引用類型最基本的分別在復(fù)制之后的結(jié)果
當(dāng)一個(gè)值類型被復(fù)制的時(shí)候,相當(dāng)于創(chuàng)造了一個(gè)完全獨(dú)立的實(shí)例,這個(gè)實(shí)例保有屬于自己的獨(dú)有數(shù)據(jù),數(shù)據(jù)不會(huì)受到其他實(shí)例的數(shù)據(jù)變化影響:
struct S { var data: Int = -1 }
var a = S()
var b = a // b 是 a 的拷貝
a.data = 42 // 更改 a 的數(shù)據(jù),b 的不受影響
println("\(a.data), \(b.data)") // 輸出結(jié)果 "42, -1"
復(fù)制一個(gè)引用類型的時(shí)候,實(shí)際上是默默地創(chuàng)造了一個(gè)共享的實(shí)例分身,兩者是共用一套數(shù)據(jù)。因此修改其中任何一個(gè)實(shí)例的數(shù)據(jù),也會(huì)影響到另外那個(gè)。
class C { var data: Int = -1 }
var x = C()
var y = x // y 是 x 的拷貝
x.data = 42 // 更改 x 的數(shù)據(jù),等于同時(shí)修改了 y
println("\(x.data), \(y.data)") // 輸出結(jié)果 "42, 42"
3、從性能出發(fā)
導(dǎo)致Swift結(jié)構(gòu)體(和枚舉)與類的性能差異的三個(gè)維度是:
- 復(fù)制消耗的成本;
- 創(chuàng)建和銷毀時(shí)花費(fèi)成本;
- 引用計(jì)數(shù)造成的成本
當(dāng)我們想要建立一個(gè)新的類型的時(shí)候,怎么決定用值類型還是引用類型呢?當(dāng)你使用 Cocoa 框架的時(shí)候,很多 API 都要通過 NSObject 的子類使用,所以這時(shí)候必須要用到引用類型 class。在其他情況下,有下面幾個(gè)準(zhǔn)則:
- 什么時(shí)候該用值類型:
- 要用==運(yùn)算符來比較實(shí)例的數(shù)據(jù)時(shí)
- 你希望那個(gè)實(shí)例的拷貝能保持獨(dú)立的狀態(tài)時(shí)
- 數(shù)據(jù)會(huì)被多個(gè)線程使用時(shí)
- 什么時(shí)候該用引用類型(class):
- 要用==運(yùn)算符來比較實(shí)例身份的時(shí)候
- 你希望有創(chuàng)建一個(gè)共享的、可變對(duì)象的時(shí)候