Struct 和Class的區(qū)別
不同點(diǎn)#####相同點(diǎn)
1.結(jié)構(gòu)體屬于值類(lèi)型,類(lèi)屬于引用類(lèi)型;
2.值類(lèi)型賦值給let var 或者函數(shù)傳參的時(shí)候完,全是深拷貝;
3.引用類(lèi)型賦值給let var 或者函數(shù)傳參的時(shí)候完,是將內(nèi)存地址拷貝一份,屬于淺拷貝;
4.結(jié)構(gòu)體屬于值類(lèi)型,標(biāo)準(zhǔn)庫(kù)中的結(jié)構(gòu)體采用copy on write策略,優(yōu)化效率;
5.結(jié)構(gòu)體不可以繼承,可以繼承;
6.都可以實(shí)現(xiàn)方法,都可以添加計(jì)算屬性和存儲(chǔ)屬性,都支持屬性監(jiān)聽(tīng),都支持?jǐn)U展.都可以遵守協(xié)議.結(jié)構(gòu)體的方法修改屬性的時(shí)候需要用@mutating修飾(枚舉也需要);
7.結(jié)構(gòu)體初始化的時(shí)候必須要給屬性賦值,來(lái)決定結(jié)構(gòu)體在內(nèi)存中的布局.Class初始化的時(shí)候可以暫時(shí)不用賦值;
8.結(jié)構(gòu)體聲明屬性的時(shí)候不需要賦值,class 聲明屬性的時(shí)候必須賦值或者包裝成Optional;
9.required關(guān)鍵字只支持Class, Class可以用static和Class 關(guān)鍵字修飾靜態(tài)方法;Struct 只能用Static 修飾;
Class的初始化
初始化required修飾的指定初始化器,子類(lèi)必須要實(shí)現(xiàn)同樣的指定初始化器,要么繼承要么在子中用required重寫(xiě)父類(lèi)的指定初始化器;
init?可失敗初始化器;
指定初始化器;
可選初始化器;
屬性觀察期
willset\didset
2,類(lèi)一定是分配在堆空間上,結(jié)構(gòu)體可能分配在堆空間:比如類(lèi)中的結(jié)構(gòu)體屬性,棧空間:比如聲明在方法中,數(shù)據(jù)段:聲明為全局變量
3.存儲(chǔ)類(lèi)型和計(jì)算類(lèi)型
都屬于實(shí)例屬性:只能通過(guò)實(shí)力去訪問(wèn)
lazy var 是一種延遲的存儲(chǔ)類(lèi)型.存儲(chǔ)屬性存儲(chǔ)在對(duì)象或者結(jié)構(gòu)體的內(nèi)存中,計(jì)算屬性不占用結(jié)構(gòu)體或者對(duì)象的屬性.
3.1類(lèi)型屬性 添加static/class修飾
整個(gè)程序運(yùn)行期,只有一份比如單例;
存儲(chǔ)類(lèi)型屬性:
計(jì)算類(lèi)型屬性:
4.屬性觀察期
非lazy的var的存儲(chǔ)屬性,計(jì)算屬性不能設(shè)置屬性觀察器;但是在初始化的時(shí)候設(shè)置不會(huì)觸發(fā)(包括在init和定義的時(shí)候賦值)
5.計(jì)算屬性和觀察期同樣適用與局部變量和全局變量
6.inout
傳入存儲(chǔ)屬性:傳入結(jié)構(gòu)體或者對(duì)象的地址,然后找到存儲(chǔ)屬性的值,直接訪問(wèn)或者修改;
傳入添加了屬性觀察器的存儲(chǔ)屬性:傳入結(jié)構(gòu)體或者對(duì)象的地址,然后在函數(shù)內(nèi)部開(kāi)辟一段局部變量作為臨時(shí)存儲(chǔ),并把這個(gè)臨時(shí)地址傳入set方法內(nèi)重新設(shè)置,在此之前會(huì)調(diào)用willset方法,設(shè)置完調(diào)用didiset方法;
傳入計(jì)算屬性:傳入結(jié)構(gòu)體或者對(duì)象的地址,然后先調(diào)用計(jì)算屬性的get方法,然后在函數(shù)內(nèi)部開(kāi)辟一段局部變量作為臨時(shí)存儲(chǔ),并把這個(gè)臨時(shí)地址傳入set方法內(nèi)重新設(shè)置.
7.方法
類(lèi)方法和實(shí)例方法 也是通過(guò)static修飾來(lái)區(qū)別.用法和OC以一樣
7.mutating 用于結(jié)構(gòu)體和枚舉這種值類(lèi)型,在自身的實(shí)例方法中修改自身屬性
struct Person {
var x = 1
mutating func add(num:Int){
x += num
}
}
var p = Person()
p.add(num: 1)
enum Dog{
case big, small
mutating func change() {
switch self {
case .big:
self = .small
case .small:
self = .big
}
}
}
var dog = Dog.big
dog.change()
print(dog)
7.@discardableResult用于消除返回函數(shù)未使用的警告
8.下標(biāo)函數(shù)
使用subscript可以給任何類(lèi)型(枚舉、結(jié)構(gòu)體棺亭、類(lèi))增加下標(biāo)功能;subscript的語(yǔ)法類(lèi)似于實(shí)例方法,計(jì)算屬性,本質(zhì)就是方法(函數(shù));
不同點(diǎn)在于結(jié)構(gòu)體中的subscript必須實(shí)現(xiàn)set方法才能通過(guò)p[0] = 10修改值,但是Class的只需要實(shí)現(xiàn)get方法就可以實(shí)現(xiàn)p[0] = 10賦值,原因是前者是值拷貝,后者是引用拷貝.
struct Person {
var x = 1, y = 1
subscript(index:Int) -> Int{
set {
if index == 0 {
x = newValue
} else {
y = newValue
}
}
get {
index == 0 ? x : y
}
}
}
var p = Person()
p[0] = 10
p[0]
9.繼承
值類(lèi)型不支持繼承,只有類(lèi)支持繼承;
swift不像OC任何類(lèi)都要繼承自某一個(gè)類(lèi);
重寫(xiě)方法重寫(xiě)下標(biāo):calss 修飾的類(lèi)型方法可以通過(guò)override重寫(xiě),但是static修飾的則不可被重寫(xiě)
重寫(xiě)實(shí)例屬性:可以把父類(lèi)的存儲(chǔ)屬性重寫(xiě)為計(jì)算屬性,只能重寫(xiě)var屬性,重寫(xiě)之后權(quán)限大于等于夫類(lèi)
重寫(xiě)類(lèi)型屬性::calss 修飾的計(jì)算屬性可以通過(guò)override重寫(xiě),但是static修飾的則不可被重寫(xiě). 存儲(chǔ)屬性不可以被calass修飾
屬性觀察期:可以在子類(lèi)中為計(jì)算屬性和存儲(chǔ)屬性添加屬性觀察,
不希望繼承重寫(xiě)用final修飾
9.1內(nèi)存結(jié)構(gòu)
前八個(gè)字節(jié)存放類(lèi)的基本信息,通過(guò)八個(gè)字節(jié)指向堆空間的一段內(nèi)存奸腺,可以找到方法實(shí)現(xiàn)挠轴。接下來(lái)的八個(gè)字節(jié)存放類(lèi)的引用計(jì)數(shù)涮拗。再往后是類(lèi)的屬性的內(nèi)存地址饶辙。
9.多態(tài)
OC:runtime
swift:通過(guò)前八個(gè)字節(jié)去查找堆上方法的實(shí)現(xiàn)
10.協(xié)議蹲诀、元類(lèi)型
Self.Type/Perosn.self是類(lèi)的原類(lèi)其實(shí)就是類(lèi)的對(duì)象的前八個(gè)字節(jié)的內(nèi)容,通過(guò)元類(lèi)型可以動(dòng)態(tài)創(chuàng)建類(lèi)的實(shí)例弃揽;
協(xié)議:可以被類(lèi)脯爪、枚舉、結(jié)構(gòu)體遵守矿微;可以繼承,可以添加屬性和方法痕慢,可以定義初始化器,協(xié)議約定的方法屬性必須要實(shí)現(xiàn)冷冗,協(xié)議可以通過(guò) & 組合作為參數(shù)的約束條件守屉,類(lèi)似于 惑艇;
Any\Anyobject\Anyclass:任意類(lèi)型蒿辙,任意對(duì)象拇泛,任意元類(lèi)對(duì)象