大家都知道swift是有值類型和應(yīng)用類型
1.值類型(Value Type):即每個實(shí)例保持一份數(shù)據(jù)拷貝。
2.引用類型(Reference Type):即所有實(shí)例共享一份數(shù)據(jù)拷貝。
區(qū)別:結(jié)構(gòu)體和class 一個是指類型一個是引用用類型 class可以繼承 結(jié)構(gòu)體不行
Swift有三種聲明類型的方式:class
,struct
和enum
培漏。它們可以分為值類型
(struct和enum)和引用類型
(class)溪厘。它們在內(nèi)存中的存儲方式不同決定它們之間的區(qū)別:
值類型是這樣一種類型胡本,當(dāng)它被賦值給一個變量、常量或者被傳遞給一個函數(shù)的時候畸悬,其值會被拷?侧甫。
實(shí)際上,Swift 中所有的基本類型:整數(shù) (integer)蹋宦、浮點(diǎn)數(shù)(floating-point number)披粟、布爾值(boolean)、字符串串(string)冷冗、數(shù)組 (array)和字典(dictionary)守屉,都是值類型,其底層是使用結(jié)構(gòu)體實(shí)現(xiàn)的蒿辙。Swift 中所有的結(jié)構(gòu)體和枚舉類型都是值類型拇泛。這意味著它們的實(shí)例例,以及實(shí)例例中所包含的任何 值類型的屬性思灌,在代碼中傳遞的時候都會被復(fù)制俺叭。
與值類型不同,引?類型在被賦予到一個變量量泰偿、常量或者被傳遞到一個函數(shù)時熄守,其值不會被拷貝。因此耗跛,使用的是已存在實(shí)例的引?裕照,而不是其拷貝。
一调塌、驗(yàn)證值類型
import UIKit
struct Point {
var x: Double
var y: Double
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let point1 = Point(x: 3, y: 5)
var point2 = point1
print(point1) // Point(x: 3.0, y: 5.0)
print(point2) // Point(x: 3.0, y: 5.0)
point2.x = 5
print(point1) // Point(x: 3.0, y: 5.0)
print(point2) // Point(x: 3.0, y: 5.0)
}
}
//打印point1 不隨著 point2 而變化 牍氛。說明他們內(nèi)存獨(dú)立
Point(x: 3.0, y: 5.0)
Point(x: 3.0, y: 5.0)
Point(x: 5.0, y: 5.0)
二、驗(yàn)證引用類型:
import UIKit
class Point {
var x: Double = 0.0
var y: Double = 0.0
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let point1 = Point()
point1.x = 3.0
point1.y = 5.0
let point2 = point1
print(point1)
print(point2)
point2.x = 5
print(point1.x , point1.y)
print(point2.x , point2.y)
}
}
//打印point1 隨著 point2 而變化 烟阐。說明他們公用一塊內(nèi)存
5.0 5.0
5.0 5.0
三搬俊、寫時復(fù)制
我們發(fā)現(xiàn) Array 這個結(jié)構(gòu)體并沒有任何 copy 相關(guān)的方法紊扬,那我們?nèi)绾巫龅缴啥鄠€完全一致卻又互不干擾的隨機(jī)數(shù)組呢?查了資料發(fā)現(xiàn)唉擂,Swift 中 值類型 有“寫時復(fù)制(Copy-On-Write)”的特性餐屎。
寫時復(fù)制可以理解為,在其中一個對象沒有作出修改時玩祟,兩個對象共享一個地址腹缩,只有當(dāng)其中一個對象發(fā)生改變之前是會同步復(fù)制生成一個新的對象。
驗(yàn)證寫時復(fù)制
首先空扎,讓我們看下面的例子我們更容易理解藏鹊,我們創(chuàng)建了數(shù)組 array1,然后將 array1 賦值給 array2转锈,再給 array2 數(shù)組添加多一個元素盘寡,我們通過查看其地址變化來確定是否進(jìn)行了拷貝行為。
let array1 = [1, 2, 3, 4]
var array2 = array1
// 斷點(diǎn)1
array2.append(2)
// 斷點(diǎn)2
print("hello world")
斷點(diǎn)1位置撮慨,使用 lldb 命令 fr v -R [object] 來查看對象內(nèi)存結(jié)構(gòu)竿痰。打印出 array1,array2 內(nèi)存結(jié)構(gòu)如下砌溺,我們可以看到 array1 和 array2 內(nèi)存地址都是 0x0000000101a1a590影涉,說明 array1 和 array2 此時是共享同一個實(shí)例
(lldb) fr v -R array1
(Swift.Array<Swift.Int>) array1 = {
_buffer = {
_storage = {
rawValue = 0x0000000101a1a590 {
Swift._ContiguousArrayStorageBase = {
Swift._SwiftNativeNSArrayWithContiguousStorage = {
Swift._SwiftNativeNSArray = {}
}
countAndCapacity = {
_storage = {
count = {
_value = 4
}
_capacityAndFlags = {
_value = 8
}
}
}
}
}
}
}
}
(lldb) fr v -R array2
(Swift.Array<Swift.Int>) array2 = {
_buffer = {
_storage = {
rawValue = 0x0000000101a1a590 {
Swift._ContiguousArrayStorageBase = {
Swift._SwiftNativeNSArrayWithContiguousStorage = {
Swift._SwiftNativeNSArray = {}
}
countAndCapacity = {
_storage = {
count = {
_value = 4
}
_capacityAndFlags = {
_value = 8
}
}
}
}
}
}
}
}
斷點(diǎn)2位置,此時 array2 添加了新元素规伐,打印 array2蟹倾,內(nèi)存結(jié)構(gòu)如下抖坪,我們可以看到 array2 內(nèi)存地址已經(jīng)變成了0x0000000101a1a5d0罚攀,說明此時它們不再共享同一個實(shí)例,array2 對應(yīng)的值進(jìn)行了拷貝行為
(lldb) fr v -R array2
(Swift.Array<Swift.Int>) array2 = {
_buffer = {
_storage = {
rawValue = 0x0000000101a1a5d0 {
Swift._ContiguousArrayStorageBase = {
Swift._SwiftNativeNSArrayWithContiguousStorage = {
Swift._SwiftNativeNSArray = {}
}
countAndCapacity = {
_storage = {
count = {
_value = 5
}
_capacityAndFlags = {
_value = 16
}
}
}
}
}
}
}
}
由此可見兽狭,array2 未做修改時萧朝,array1 和 array2 是共享同一個實(shí)例岔留。