在swift中型別其實就分為兩類:
值型別(value types):每個例項都保留乙份獨有的資料拷貝,一般以結構體 (struct) 、 列舉(enu
m) 或者元組(tuple)的形式出現。
引用型別(reference types):
每個例項共享乙份資料**,一般以類(class)的形式出現。
具體是什麼意思呢?看看下面的例子就明白了。
建立乙個person類,裡面有乙個name屬性:
class person
}var var1 = person(name: "john")
此時,var1在記憶體中是這樣的:
建立乙個新的變數var2讓它等於var1:
var var2 = var1
此時,var1 和 var2 指向了記憶體中的同乙個地方:
上文我們說class是引用型別,顧名思義,"引用"就是c語言中的指標,指標是乙個位址,指向某個記憶體,因此類的變數實際上是儲存了例項的位址,當我們宣告乙個新的變數var2 = var1時,並沒有建立乙個新的例項,而是把var1例項的位址賦值給var2,於是就有了圖2。
知道了類例項的儲存機制,下面這種現象就非常容易理解了:
var1.name = "jane"
print(var1.name) // jane
print(var2.name) //jane
我們只改變了變數var1的name屬性,發現var2的name屬性也發生了變化。原因非常明顯,因為var1和var2是共享同乙個例項,當使用變數var1修改了其所指向的例項之後,var2對應的例項自然也就被修改了。
同樣的,我們以struct為例來說明值型別:
建立乙個person結構體,裡面有乙個name屬性:
struct person
var var1 = person(name: "john")
此時,var1中儲存的不是指向記憶體的指標,而是值:
建立乙個新的例項var2,並賦值為var1:
var var2 = var1
此時,系統將會建立乙個新的例項並將var1中的值拷貝乙份,如下圖所示:
因此,當修改var1中的屬性時,var2的值是不會發生改變的:
var1.name = "jane"
print(var1.name) //jane
print(var2.name) //john
可以看到var2還是保持原來的值,因為在執行var2 = var1時,系統拷貝了乙個新的例項給var2,那麼var1與var2之間是不會相互影響的。
值型別和引用型別有各自的優缺點,我們應該根據具體的需求來選擇。
堆和棧是記憶體中不同的分割槽,它們與引用型別和值型別有很多的聯絡。
棧(stack):當我們建立乙個值型別,如結構體,系統將其儲存在乙個被稱為棧的記憶體區域中。系統使用棧來儲存在緊急執行緒上的任何東西,是由cpu直接管理和優化的。當乙個函式宣告乙個變數,變數將儲存在棧中,當函式呼叫完畢後棧會自動釋放該變數。因此棧是非常易於管理的、有效的,由於是cpu直接控制,速度非常快。
堆(heap):當我們建立了乙個引用型別,如類,系統將把類例項儲存在乙個被稱為堆的記憶體區域中。系統使用堆來儲存其他物件引用的資料。堆是乙個大的記憶體池,系統可以從該池中請求並動態分配記憶體塊。堆不會像棧一樣自動釋放物件,需要額外的工作來完成。這使得在堆中建立和刪除資料比棧慢。
下圖展示了類的例項在堆和棧中的儲存:
當我們建立乙個類的例項時,系統會在堆中申請乙個記憶體塊用於儲存例項本身,如圖中右邊heap中的兩個例項。同時將把儲存該例項的變數和堆中的位址儲存在棧中,如圖的左邊所示。
而當建立乙個結構體時,將會把變數和值都儲存在棧中。
Swift值型別和引用型別
的乙份,比如結構體 struct 列舉 enum 元組 tuple 都是值型別。第二種是引用型別,該型別的例項共享資料唯一的乙份副本 在native層面說的話,就是該型別的每個例項都指向記憶體中的同乙個位址 比如類 class 就是引用型別。在這篇文章中,我們將深入 值型別和引用型別的使用價值,以及...
Swift 值型別和引用型別
swift中有兩種型別 值型別 value type 引用型別 reference type 在swift中,所有的基本型別 整型 int 浮點型 float 布林型別 boolean 字串型別 string 陣列 array 字典 dictionary 元組 tuple 都是值型別,它們的底層都是...
swift 值型別和引用型別
值型別被賦予給乙個變數,常數或者本身被傳遞給乙個函式的時候,實際上操作的是其的拷貝。在 swift 中,所有的基本型別 整數 integer 浮點數 floating point 布林值 booleans 字串 string 陣列 array 和字典 dictionaries 都是值型別,並且都是以...