結(jié)構(gòu)體
一稳懒、結(jié)構(gòu)體 是值類型
二儡羔、結(jié)構(gòu)體的存儲位置
結(jié)構(gòu)體的存儲位置 根據(jù)不同情況來分
1程癌、如果結(jié)構(gòu)體(值類型)在函數(shù)中創(chuàng)建 它存儲在椬烊浚空間
例如:
func testStruct(){
struct Point {
var x: Int = 0
var y: Int = 0
}
var p = Point()
}
由于結(jié)構(gòu)體在 testStruct 函數(shù)中創(chuàng)建 所以他存儲在 椛ㄍ猓空間
2、 如果值類型在全局區(qū)創(chuàng)建的 它存儲在代碼區(qū)
例如:
import Foundation
struct Point {
var x: Int
var y: Int
}
var p = Point.init(x: 10, y: 10)
三廓脆、說明 + 示例
在swift標(biāo)準(zhǔn)庫中畏浆。絕大數(shù)的公開類都是結(jié)構(gòu)體。而枚舉和類只占很小一部分
比如 Bool狞贱、 Int 刻获、Double、 String 瞎嬉、Array蝎毡、 Dictionary
所有的結(jié)構(gòu)體 都有編譯器自動生成的初始化器
編譯器會根據(jù)實際情況 可能會為結(jié)構(gòu)體生成多個初始化器
生成初始化器的宗旨是:保證所有成員都有初始值(這是秘訣 要記住)
例如下面的幾種類型
1氧枣、Point x 和 y 沒有初始值
struct Point {
var x: Int
var y: Int
}
//由于初始化器的宗旨是:保證所有成員都有初始值
// Point 中 的 x 和 y 都沒有初始值
// 所以編譯器自動給Point 生成一個兩個參數(shù)的初始化器
var p = Point.init(x: 10, y: 10)
2沐兵、Point1 x沒有初始值 y有初始值
struct Point1 {
var x: Int
var y: Int = 10
}
//由于初始化器的宗旨是:保證所有成員都有初始值
// Point1 中 的 x沒有初始值 y有初始值
// 所以編譯器自動給Point1 生成如下兩個初始化器
var p1 = Point1.init(x: 10, y: 30)
var p11 = Point1.init(x: 30)
3、Point2 x和y都有初始值
struct Point2 {
var x: Int = 20
var y: Int = 10
}
//由于初始化器的宗旨是:保證所有成員都有初始值
// Point2 中 的 x 和 y 都有初始值
// 所以編譯器自動給Point2 生成如下四個初始化器
var p21 = Point2.init(x: 0, y: 20)
var p22 = Point2.init(x:0)
var p23 = Point2.init(y:0)
var p24 = Point2.init()
4便监、Point3 x和y都為可選型 (因為可選型初始值 都為nil)
struct Point3 {
var x: Int?
var y: Int?
}
//由于初始化器的宗旨是:保證所有成員都有初始值
// Point3 中 的 x 和 y 都為可選型
// 由于可選型都有默認(rèn)值 nil
// 所以編譯器自動給Point3 生成如下四個初始化器
var p31 = Point3.init(x: 0, y: 20)
var p32 = Point3.init(x:0)
var p33 = Point3.init(y:0)
var p34 = Point3.init()
自定義初始化器
注意??:一旦定義了結(jié)構(gòu)體的初始化器 編譯器就不會幫助它生成其他的初始化器
例如
struct Point4 {
var x: Int = 0
var y: Int = 0
init(x: Int,y: Int){
self.x = x
self.y = y
}
}
//由于我們自定義了一個初始化器 所以編譯器就不會再為我們生成初始化器
//所以 我們 初始化Point4 只能用我們自己定義的
var p4 = Point4.init(x: 10, y: 20)
類
一扎谎、類 是引用類型 (指針類型)
類的定義和結(jié)構(gòu)體類似 但是編譯器不會為類自動生成可傳入成員值的初始化器
注意??:
如果類的所有成員都在定義的時候指定了類初始值 編譯器就會為類生成無參的初始化器
成員的初始化就是在無參的初始化器中完成的
例如
class Point {
var x: Int = 0
var y: Int = 1
}
// 因為 類的所有成員都在定義的時候指定了類初始值
//所以編譯器為Point 自動生成了一個初始化器
let p1 = Point.init()
類 和 結(jié)構(gòu)體 的本質(zhì)區(qū)別
在swift中 結(jié)構(gòu)體和類 都能定義方法
結(jié)構(gòu)體是值類型
枚舉也是值類型
類是引用類型(指針類型)
舉例說明
struct Point {
var x: Int = 3
var y: Int = 4
}
class Size {
var width = 1
var hight = 2
}
func test(){
var point = Point()
var size = Size()
}
text 函數(shù)在椞枷耄空間的分布情況如下圖所示 (假設(shè)開始地址是 0x10000)
解析:
由于 text 是一個函數(shù) 所以他存儲在椈侔校空間
楇时迹空間 前16個字節(jié) 分別存放 Point (值類型)的兩個成員變量的值
后8個字節(jié) 存放的 是一個指針變量(也就是 size size是一個指針)
size 指針變量內(nèi)存中存放的是 size對象內(nèi)存地址(這個地址是在堆空間 因為size是一個對象 創(chuàng)建的時候需要 alloc 開辟堆空間)
size對象的前 8個字節(jié) 存放的是 類型信息的地址 它指向size的元類 元類來存放類的一些信息(如:方法、類方法)
8--16個字節(jié) 存放的是 對象的引用計數(shù)
后面就是存放類的一些成員信息
值類型 與 引用類型的區(qū)別
值類型 賦值給 var预吆、let 或者 給函數(shù)傳參 是直接將內(nèi)容拷貝一份 會產(chǎn)生全新的文件副本
修改 原數(shù)據(jù) 對 副本沒有任何影響
修給 副本 對 原數(shù)據(jù)沒有任何影響
注意??:
在Swift標(biāo)準(zhǔn)庫中龙填,為了提升性能,String拐叉、Array岩遗、Dictionary、Set采取了Copy On Write的技術(shù) (也就是說 只有在對其進行修改的時候才會去深度拷貝 如果不修改僅僅是淺拷貝)
比如僅當(dāng)有“寫”操作時凤瘦,才會真正執(zhí)行拷貝操作
對于標(biāo)準(zhǔn)庫值類型的賦值操作宿礁,Swift 能確保最佳性能,所有沒必要為了保證最佳性能來避免賦值
建議:不需要修改 盡量換成let
例如
var s1 = "Jack"
var s2 = s1
print(s1)
s2.append("_Rose")
print(s2)
當(dāng)代碼走到14行時 s1 和 s2 他們倆指向的是同一塊內(nèi)存 如下圖所示
當(dāng)代碼走到16行時 s1 和 s2 他們倆指向的是不同內(nèi)存 如下圖所示
原因是因為 s2 進行了改寫 所以就就調(diào)用 copy