一吨些、基礎(chǔ)
1鹏倘、final關(guān)鍵詞的用法
final關(guān)鍵詞的作用:它修飾的類遏片、方法嘹害、變量是不能被繼承或重寫的撮竿,編譯器會(huì)報(bào)錯(cuò)。另外笔呀,通過(guò)它可以顯示的指定函數(shù)的派發(fā)機(jī)制
2幢踏、常見的數(shù)據(jù)類型
常見的數(shù)據(jù)類型 | ||
---|---|---|
枚舉(enum) | Optional | |
值類型(value type) | 結(jié)構(gòu)體(struct) | Bool、Int许师、Float房蝉、Double、Character |
String微渠、Array搭幻、Dictionary、Set | ||
引用類型(reference type) | 類(class) |
3逞盆、函數(shù)重載
1. 規(guī)則
函數(shù)名相同
參數(shù)個(gè)數(shù)不同 || 參數(shù)類型不同 || 參數(shù)標(biāo)簽不同
2.注意
返回值類型與函數(shù)重載無(wú)關(guān)
默認(rèn)參數(shù)值和函數(shù)重載一起使用產(chǎn)生二義性時(shí)檀蹋,編譯器并不會(huì)報(bào)錯(cuò)(c++會(huì)報(bào)錯(cuò))
可變參數(shù)、省略函數(shù)標(biāo)簽纳击、函數(shù)重載一起使用產(chǎn)生二義性時(shí)续扔,編譯器有可能會(huì)報(bào)錯(cuò)
4、內(nèi)聯(lián)函數(shù)
如果開啟了編譯器優(yōu)化(Release模式默認(rèn)會(huì)開啟優(yōu)化)焕数,編譯器會(huì)自動(dòng)將某些函數(shù)變成內(nèi)聯(lián)函數(shù)
將函數(shù)調(diào)用展開成函數(shù)體
1、哪些函數(shù)不會(huì)被自動(dòng)內(nèi)聯(lián)刨啸?
- 函數(shù)體比較長(zhǎng)
- 包含遞歸調(diào)用
- 包含動(dòng)態(tài)派發(fā)
// 永遠(yuǎn)不會(huì)被內(nèi)聯(lián)(即使開啟了編譯器優(yōu)化)
@inline(never) func test() {
print("test")
}
// 開啟編譯器優(yōu)化后堡赔,即使代碼很長(zhǎng),也會(huì)被內(nèi)聯(lián)(遞歸調(diào)用函數(shù)设联、動(dòng)態(tài)派發(fā)的函數(shù)除外)
@inline(__always) func test() {
print("test")
}
在Release模式下善已,編譯器已經(jīng)開啟優(yōu)化,會(huì)自動(dòng)決定哪些函數(shù)需要內(nèi)聯(lián)离例,因此沒必要使用
5换团、遞歸枚舉
遞歸枚舉是一種枚舉類型,它有一個(gè)或多個(gè)枚舉成員使用該枚舉類型的實(shí)例作為關(guān)聯(lián)值宫蛆。使用遞歸枚舉時(shí)艘包,編譯器會(huì)插入一個(gè)間接層。你可以在枚舉成員前加上 indirect 來(lái)表示該成員可遞歸
enum ArithmeticExpression {
case number(Int)
indirect case addition(ArithmeticExpression, ArithmeticExpression)
indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}
// 你也可以在枚舉類型開頭加上 indirect 關(guān)鍵字來(lái)表明它的所有成員都是可遞歸的:
// 定義的枚舉類型可以存儲(chǔ)三種算術(shù)表達(dá)式:純數(shù)字耀盗、兩個(gè)表達(dá)式相加想虎、兩個(gè)表達(dá)式相乘。枚舉成員 addition 和 multiplication 的關(guān)聯(lián)值也是算術(shù)表達(dá)式——這些關(guān)聯(lián)值使得嵌套表達(dá)式成為可能叛拷。
indirect enum ArithmeticExpression {
case number(Int)
case addition(ArithmeticExpression, ArithmeticExpression)
case multiplication(ArithmeticExpression, ArithmeticExpression)
}
// 使用 ArithmeticExpression 這個(gè)遞歸枚舉創(chuàng)建表達(dá)式 (5 + 4) * 2
let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
// 算術(shù)表達(dá)式求值的函數(shù)
// 該函數(shù)如果遇到純數(shù)字舌厨,就直接返回該數(shù)字的值。如果遇到的是加法或乘法運(yùn)算忿薇,則分別計(jì)算左邊表達(dá)式和右邊表達(dá)式的值裙椭,然后相加或相乘躏哩。
func evaluate(_ expression: ArithmeticExpression) -> Int {
switch expression {
case let .number(value):
return value
case let .addition(left, right):
return evaluate(left) + evaluate(right)
case let .multiplication(left, right):
return evaluate(left) * evaluate(right)
}
}
print(evaluate(product)) // 打印“18”
6、MemoryLayout
/// 用法一
MemoryLayout<password>.stride // 分配的占用內(nèi)存
MemoryLayout<password>.size // 實(shí)際的內(nèi)存大小
MemoryLayout<password>.alignment // 對(duì)齊參數(shù)
/// 用法二
let pwd = password.number(1, 1, 1, 1)
MemoryLayout.stride(ofValue: pwd)
MemoryLayout.size(ofValue: pwd)
MemoryLayout.alignment(ofValue: pwd)
7揉燃、關(guān)聯(lián)值跟原始值的區(qū)別
- 枚舉類型變量會(huì)占用1個(gè)字節(jié) 不論枚舉變量類型是Int還是String 都不會(huì)根據(jù)定義類型來(lái)計(jì)算字節(jié)大小
- 關(guān)聯(lián)值跟原始值的區(qū)別
1扫尺、關(guān)聯(lián)類型的枚舉,其實(shí)是會(huì)存儲(chǔ)對(duì)應(yīng)的關(guān)聯(lián)類型的值的你雌,關(guān)聯(lián)類型占用多少個(gè)字節(jié)就影響枚舉的內(nèi)存
關(guān)聯(lián)值會(huì)占用枚舉變量的內(nèi)存器联,會(huì)根據(jù)外界傳值類型計(jì)算大小
2、原始值不允許你自定義婿崭,也不會(huì)根據(jù)枚舉類型計(jì)算內(nèi)存大小
原始值不會(huì)占用枚舉變量的內(nèi)存拨拓,只會(huì)占用1個(gè)字節(jié),用來(lái)標(biāo)記枚舉類型
8氓栈、類跟結(jié)構(gòu)體的區(qū)別
本質(zhì)區(qū)別:結(jié)構(gòu)體(枚舉)是值類型渣磷,類是引用類型(指針類型)
結(jié)構(gòu)體:
1.編譯器會(huì)根據(jù)情況,可能會(huì)為結(jié)構(gòu)體生成多個(gè)初始化器授瘦,宗旨是:保證所有成員都有初始值
2.一旦在定義結(jié)構(gòu)體時(shí)自定義了初始化器醋界,編譯器就不會(huì)再幫它自動(dòng)生成其他初始化器
類:
1.類的定義和結(jié)構(gòu)體類似,但編譯器并沒有為類自動(dòng)生成可以傳入成員值的初始化器
2.如果類的所有成員都在定義的時(shí)候指定了初始值提完,編譯器會(huì)為類生成無(wú)參的初始化器
3.成員的初始化是在這個(gè)初始化器中完成的
9形纺、值類型與引用類型
值類型
值類型賦值給var、let或者給函數(shù)傳參徒欣,是直接將所有內(nèi)容拷貝一份
類似于對(duì)文件進(jìn)行copy逐样、paste操作,產(chǎn)生了全新的文件副本打肝。屬于深拷貝(deep copy)
引用類型
引用賦值給var脂新、let或者給函數(shù)傳參,是將內(nèi)存地址拷貝一份
類似于制作一個(gè)文件的替身(快捷方式粗梭、鏈接)争便,指向的是同一個(gè)文件。屬于淺拷貝(shallow copy)
10断医、閉包(引用類型)
https://wenku.baidu.com/view/c69d9f4e26c52cc58bd63186bceb19e8b9f6ec56.html
1滞乙、閉包
是我們最常用的閉包的一種,是一個(gè)利用輕量級(jí)語(yǔ)法所寫的可以捕獲其上下文中變量或常量值的匿名閉包
1.閉包捕獲值的本質(zhì)是在堆區(qū)開辟內(nèi)存然后存儲(chǔ)其在上下文中捕獲到的值
2.修改值也是修改的堆空間的值
3.閉包是一個(gè)引用類型
4.閉包的底層結(jié)構(gòu)是一個(gè)結(jié)構(gòu)體
- 首先存儲(chǔ)閉包的地址
- 加上捕獲值的地址
5.在捕獲的值中孩锡,會(huì)對(duì)定義的變量和函數(shù)中的參數(shù)分開存儲(chǔ)
6.存儲(chǔ)的時(shí)候內(nèi)部會(huì)有一個(gè)HeapObject結(jié)構(gòu)酷宵,用于管理內(nèi)存,引用計(jì)數(shù)
7.函數(shù)是特殊的閉包躬窜,只不過(guò)函數(shù)不捕獲值浇垦,所以在閉包結(jié)構(gòu)體中只存儲(chǔ)函數(shù)地址,不存儲(chǔ)指向捕獲值的指針
使用閉包有很多好處:
1.可以利用上下文自動(dòng)推斷參數(shù)和返回值的類型
2.隱士返回單表達(dá)式閉包荣挨,也就是但表達(dá)式的時(shí)候可以省略return關(guān)鍵字
3.參數(shù)名稱可以簡(jiǎn)寫或者不寫男韧,使用$0表示第一個(gè)參數(shù)
4.尾隨閉包表達(dá)式
2朴摊、自動(dòng)閉包
- 自動(dòng)閉包是一種自動(dòng)創(chuàng)建的閉包,用于包裝傳遞給函數(shù)作為參數(shù)的表達(dá)式此虑。
- 這種閉包不接受任何參數(shù)甚纲,當(dāng)它被調(diào)用的時(shí)候,會(huì)返回被包裝在其中的表達(dá)式的值朦前。
- 這種便利語(yǔ)法讓你能夠省略閉包的花括號(hào)介杆,用一個(gè)普通的表達(dá)式來(lái)代替顯式的閉包。
- 自動(dòng)閉包讓你能夠延遲求值韭寸,因?yàn)橹钡侥阏{(diào)用這個(gè)閉包春哨,代碼段才會(huì)被執(zhí)行。
- 延遲求值對(duì)于那些有副作用(Side Effect)和高計(jì)算成本的代碼來(lái)說(shuō)是很有益處的恩伺,因?yàn)樗沟媚隳芸刂拼a的執(zhí)行時(shí)機(jī)赴背。
3、尾隨閉包
11晶渠、逃逸閉包&非逃逸閉包
1凰荚、非逃逸閉包的特性
Swift 3.0之后,系統(tǒng)默認(rèn)閉包參數(shù)就是被@noescapeing修飾的
執(zhí)行時(shí)機(jī):在函數(shù)體內(nèi)執(zhí)行
聲明周期:在函數(shù)執(zhí)行完后褒脯,閉包也就消失了
2便瑟、逃逸閉包
逃逸閉包的定義:當(dāng)閉包作為一個(gè)實(shí)際參數(shù)傳遞給一個(gè)函數(shù)的時(shí)候,并且是在函數(shù)返回之后調(diào)用番川,我們就說(shuō)這個(gè)閉包逃逸了胳徽。當(dāng)我們聲明一個(gè)接受閉包作為形式參數(shù)的函數(shù)時(shí),你可以在形式參數(shù)前些@escapeing來(lái)明確閉包是允許逃逸的爽彤。
另外使用@escapeing修飾的閉包在其閉包體內(nèi)需要顯示的使用self,對(duì)于顯示的使用self主要是希望開發(fā)者注意循環(huán)引用缚陷。
逃逸閉包的使用時(shí)機(jī)分為以下兩種情況:
保存在一個(gè)函數(shù)外部定義的變量中
延遲調(diào)用
總結(jié)
關(guān)于逃逸閉包和非逃逸閉包基本就說(shuō)完了适篙,下面稍作總結(jié):
1.首先兩者都是作為函數(shù)參數(shù)
2.非逃逸閉包在函數(shù)中調(diào)用,并且是函數(shù)結(jié)束前就調(diào)用完成
3.非逃逸閉包不會(huì)產(chǎn)生循環(huán)引用箫爷,因?yàn)樽饔糜蛟诤瘮?shù)內(nèi)嚷节,函數(shù)執(zhí)行完畢會(huì)釋放函數(shù)內(nèi)的所有對(duì)象
4.針對(duì)非逃逸閉包編譯器會(huì)優(yōu)化內(nèi)存管理的調(diào)用
5.根據(jù)官方文檔的說(shuō)明,非逃逸閉包會(huì)保存在棧上(未驗(yàn)證出來(lái))
6.逃逸閉包在函數(shù)返回后才會(huì)調(diào)用虎锚,也就是閉包逃離出了函數(shù)的作用域
7.逃逸閉包中可能會(huì)產(chǎn)生循環(huán)引用
8.逃逸閉包中需要顯示的引用self硫痰,主要作用是提醒開發(fā)者注意循環(huán)引用
12、解決循環(huán)引用
1窜护、weak也是我們OC中的一種解決循環(huán)引用的方式效斑,在Swift中使用weak修飾的實(shí)例變量默認(rèn)為可選類型,所以在使用weak后p對(duì)象會(huì)成為可選類型柱徙,在使用的時(shí)候需要使用?或者!
func test() {
var p = Person()
p.myClourse = { [weak p] in
p?.age += 1
}
}
2缓屠、unowned也是Swift中獨(dú)有的一種解決循環(huán)引用的方式奇昙,相較于weak,使用unowned修飾后的對(duì)象不是可選類型敌完,也不可置為nil储耐。unowned的意思是假定當(dāng)前對(duì)象有值,所以就可能存在野指針的情況滨溉,所以在使用的過(guò)程中要注意使用的位置什湘。而weak修飾的對(duì)象一旦為nil的時(shí)候,由于swift特性晦攒,可選值為nil就不會(huì)執(zhí)行后續(xù)的代碼闽撤,相較于unowned比較安全
func test() {
var p = Person()
p.myClourse = { [unowned p] in
p.age += 1
}
}
13、捕獲列表
在上文中我們提到的[weak p]和[unowned p]在swift中被稱為捕獲列表
捕獲列表:
定義在閉包的參數(shù)列表之前
- 使用[]括起來(lái)
- 即使是省略參數(shù)和返回值的時(shí)候也要使用in關(guān)鍵字
- [weak p]和[unowned p]是分別使用weak和unowned關(guān)鍵字修飾p
- 如果不需要修飾勤家,我們可以寫成[p]
對(duì)于閉包中捕獲列表中的常量腹尖,閉包會(huì)捕獲外部相同名稱的變量或常量來(lái)初始化捕獲列表中定義的常量,其有如下特點(diǎn):
1.捕獲列表中的是常量伐脖,不可修改
2.該常量是值拷貝热幔,相當(dāng)于復(fù)制了一份外部變量或常量
3.既然是常量就是不可修改的
14、屬性
Swift中跟實(shí)例相關(guān)的屬性可以分為2大類
1.存儲(chǔ)屬性(Stored Property)
類似于成員變量這個(gè)概念
存儲(chǔ)在實(shí)例的內(nèi)存中
結(jié)構(gòu)體讼庇、類可以定義存儲(chǔ)屬性
枚舉不可以定義存儲(chǔ)屬性
2.計(jì)算屬性(Computed Property)
本質(zhì)就是方法(函數(shù))
不占用實(shí)例的內(nèi)存
枚舉绎巨、結(jié)構(gòu)體、類都可以定義計(jì)算屬性
15蠕啄、inout
1.如果實(shí)參有物理內(nèi)存地址场勤,且沒有設(shè)置屬性觀察器
直接將實(shí)參的內(nèi)存地址傳入函數(shù)(實(shí)參進(jìn)行引用傳遞)
2.如果實(shí)參是計(jì)算屬性或者設(shè)置了屬性觀察器
采取了Copy In Copy Out的做法
- 調(diào)用該函數(shù)時(shí),先復(fù)制實(shí)參的值歼跟,產(chǎn)生副本【get】
- 將副本的內(nèi)存地址傳入函數(shù)(副本進(jìn)行引用傳遞)和媳,在函數(shù)內(nèi)部可以修改副本的值
- 函數(shù)返回后,再將副本的值覆蓋實(shí)參的值【set】
3.總結(jié):inout的本質(zhì)就是引用傳遞(地址傳遞)
16哈街、類型屬性
嚴(yán)格來(lái)說(shuō)留瞳,屬性可以分為
實(shí)例屬性(Instance Property):只能通過(guò)實(shí)例去訪問(wèn)
??存儲(chǔ)實(shí)例屬性(Stored Instance Property):存儲(chǔ)在實(shí)例的內(nèi)存中,每個(gè)實(shí)例都有1份
??計(jì)算實(shí)例屬性(Computed Instance Property)
類型屬性(Type Property):只能通過(guò)類型去訪問(wèn)
??存儲(chǔ)類型屬性(Stored Type Property):整個(gè)程序運(yùn)行過(guò)程中骚秦,就只有1份內(nèi)存(類似于全局變量)
??計(jì)算類型屬性(Computed Type Property)
可以通過(guò)static定義類型屬性
如果是類她倘,也可以用關(guān)鍵字class
類型屬性細(xì)節(jié)
1.不同于存儲(chǔ)實(shí)例屬性,你必須給存儲(chǔ)類型屬性設(shè)定初始值
因?yàn)轭愋蜎]有像實(shí)例那樣的init初始化器來(lái)初始化存儲(chǔ)屬性
2.存儲(chǔ)類型屬性默認(rèn)就是lazy作箍,會(huì)在第一次使用的時(shí)候才初始化
就算被多個(gè)線程同時(shí)訪問(wèn)硬梁,保證只會(huì)初始化一次
存儲(chǔ)類型屬性可以是let
3.枚舉類型也可以定義類型屬性(存儲(chǔ)類型屬性、計(jì)算類型屬性)
17胞得、方法
枚舉荧止、結(jié)構(gòu)體、類都可以定義實(shí)例方法、類型方法
實(shí)例方法(Instance Method):通過(guò)實(shí)例對(duì)象調(diào)用
類型方法(Type Method):通過(guò)類型調(diào)用罩息,用static或者class關(guān)鍵字定義
self
在實(shí)例方法中代表實(shí)例對(duì)象
在類型方法中代表類型
18嗤详、mutating
結(jié)構(gòu)體和枚舉是值類型,默認(rèn)情況下瓷炮,值類型的屬性不能被自身的實(shí)例方法修改
在func關(guān)鍵字前加mutating可以允許這種修改行為
只有將協(xié)議中的實(shí)例方法標(biāo)記為mutating
才允許結(jié)構(gòu)體葱色、枚舉的具體實(shí)現(xiàn)修改自身內(nèi)存
類在實(shí)現(xiàn)方法時(shí)不用加mutating,枚舉娘香、結(jié)構(gòu)體才需要加mutating
19苍狰、@discardableResult
在func前面加個(gè)@discardableResult,可以消除:函數(shù)調(diào)用后返回值未被使用的警告?
20烘绽、重寫類型方法淋昭、下標(biāo)
被class修飾的類型方法、下標(biāo)安接,允許被子類重寫
被static修飾的類型方法翔忽、下標(biāo),不允許被子類重寫
21盏檐、重寫屬性
1歇式、子類可以將父類的屬性(存儲(chǔ)、計(jì)算)重寫為計(jì)算屬性
2胡野、子類不可以將父類屬性重寫為存儲(chǔ)屬性
3材失、只能重寫var屬性,不能重寫let屬性
4硫豆、重寫時(shí)龙巨,屬性名、類型要一致
5熊响、子類重寫后的屬性權(quán)限不能小于父類屬性的權(quán)限
- 如果父類屬性是只讀的旨别,那么子類重寫后的屬性可以是只讀的、也可以是可讀寫的
- 如果父類屬性是可讀寫的汗茄,那么子類重寫后的屬性也必須是可讀寫的
22昼榛、重寫類型屬性
被class修飾的計(jì)算類型屬性,可以被子類重寫
被static修飾的類型屬性(存儲(chǔ)剔难、計(jì)算),不可以被子類重寫
23奥喻、final
被final修飾的方法偶宫、下標(biāo)、屬性环鲤,禁止被重寫
被final修飾的類纯趋,禁止被繼承
24、兩段式初始化
Swift在編碼安全方面是煞費(fèi)苦心,為了保證初始化過(guò)程的安全吵冒,設(shè)定了兩段式初始化纯命、安全檢查
*兩段式初始化
第1階段:初始化所有存儲(chǔ)屬性
① 外層調(diào)用指定\便捷初始化器
② 分配內(nèi)存給實(shí)例,但未初始化
③ 指定初始化器確保當(dāng)前類定義的存儲(chǔ)屬性都初始化
④ 指定初始化器調(diào)用父類的初始化器痹栖,不斷向上調(diào)用亿汞,形成初始化器鏈
第2階段:設(shè)置新的存儲(chǔ)屬性值
① 從頂部初始化器往下,鏈中的每一個(gè)指定初始化器都有機(jī)會(huì)進(jìn)一步定制實(shí)例
② 初始化器現(xiàn)在能夠使用self(訪問(wèn)揪阿、修改它的屬性疗我,調(diào)用它的實(shí)例方法等等)
③ 最終,鏈中任何便捷初始化器都有機(jī)會(huì)定制實(shí)例以及使用self
25南捂、安全檢查
① 指定初始化器必須保證在調(diào)用父類初始化器之前吴裤,其所在類定義的所有存儲(chǔ)屬性都要初始化完成
② 指定初始化器必須先調(diào)用父類初始化器,然后才能為繼承的屬性設(shè)置新值
③ 便捷初始化器必須先調(diào)用同類中的其它初始化器溺健,然后再為任意屬性設(shè)置新值
④ 初始化器在第1階段初始化完成之前麦牺,不能調(diào)用任何實(shí)例方法、不能讀取任何實(shí)例屬性的值鞭缭,也不能引用self
⑤ 直到第1階段結(jié)束剖膳,實(shí)例才算完全合法
26、初始化器
單獨(dú)init修飾的為指定初始化器
convenience修飾的為便捷初始化器
// 指定初始化器
//init(parametets) {
// statements
//}
// 便捷初始化器
//convenience init(parametets) {
// statements
//}
27缚去、重寫
① 當(dāng)重寫父類的指定初始化器時(shí)潮秘,必須加上override(即使子類的實(shí)現(xiàn)是便捷初始化器)
② 如果子類寫了一個(gè)匹配父類便捷初始化器的初始化器,不用加上override
因?yàn)楦割惖谋憬莩跏蓟饔肋h(yuǎn)不會(huì)通過(guò)子類直接調(diào)用易结,因此枕荞,嚴(yán)格來(lái)說(shuō),子類無(wú)法重寫父類的便捷初始化器
28搞动、自動(dòng)繼承
① 如果子類沒有自定義任何指定初始化器躏精,它會(huì)自動(dòng)繼承父類所有的指定初始化器
② 如果子類提供了父類所有指定初始化器的實(shí)現(xiàn)(要么通過(guò)方式①繼承,要么重寫)
子類自動(dòng)繼承所有的父類便捷初始化器
③ 就算子類添加了更多的便捷初始化器鹦肿,這些規(guī)則仍然適用
④ 子類以便捷初始化器的形式重寫父類的指定初始化器矗烛,也可以作為滿足規(guī)則②的一部分
29、required
用required修飾指定初始化器箩溃,表明其所有子類都必須實(shí)現(xiàn)該初始化器(通過(guò)繼承或者重寫實(shí)現(xiàn))
如果子類重寫了required初始化器瞭吃,也必須加上required,不用加override
30涣旨、屬性觀察器
父類的屬性在它自己的初始化器中賦值不會(huì)觸發(fā)屬性觀察器歪架,但在子類的初始化器中賦值會(huì)觸發(fā)屬性觀察器
31、可失敗初始化器
類霹陡、結(jié)構(gòu)體和蚪、枚舉都可以使用init?定義可失敗初始化器
不允許同時(shí)定義參數(shù)標(biāo)簽止状、參數(shù)個(gè)數(shù)、參數(shù)類型相同的可失敗初始化器和非可失敗初始化器
可以用init!定義隱式解包的可失敗初始化器
可失敗初始化器可以調(diào)用非可失敗初始化器攒霹,非可失敗初始化器調(diào)用可失敗初始化器需要進(jìn)行解包
如果初始化器調(diào)用一個(gè)可失敗初始化器導(dǎo)致初始化失敗怯疤,那么整個(gè)初始化過(guò)程都失敗,并且之后的代碼都停止執(zhí)行
可以用一個(gè)非可失敗初始化器重寫一個(gè)可失敗初始化器催束,但反過(guò)來(lái)是不行的
32集峦、反初始化器(deinit)
deinit叫做反初始化器,類似于C++的析構(gòu)函數(shù)泣崩、OC中的dealloc方法
當(dāng)類的實(shí)例對(duì)象被釋放內(nèi)存時(shí)少梁,就會(huì)調(diào)用實(shí)例對(duì)象的deinit方法
class Person {
deinit {
print("Person對(duì)象銷毀了")
}
}
deinit不接受任何參數(shù),不能寫小括號(hào)矫付,不能自行調(diào)用
父類的deinit能被子類繼承
子類的deinit實(shí)現(xiàn)執(zhí)行完畢后會(huì)調(diào)用父類的deinit
33凯沪、可選鏈
① 如果可選項(xiàng)為nil,調(diào)用方法买优、下標(biāo)妨马、屬性失敗,結(jié)果為nil
② 如果可選項(xiàng)不為nil杀赢,調(diào)用方法烘跺、下標(biāo)、屬性成功脂崔,結(jié)果會(huì)被包裝成可選項(xiàng)
③ 如果結(jié)果本來(lái)就是可選項(xiàng)滤淳,不會(huì)進(jìn)行再次包裝
多個(gè)?可以鏈接在一起
如果鏈中任何一個(gè)節(jié)點(diǎn)是nil,那么整個(gè)鏈就會(huì)調(diào)用失敗
34砌左、協(xié)議(procotol)
協(xié)議可以用來(lái)定義方法脖咐、屬性、下標(biāo)的聲明汇歹,協(xié)議可以被枚舉屁擅、結(jié)構(gòu)體、類遵守(多個(gè)協(xié)議之間用逗號(hào)隔開)
協(xié)議中定義方法時(shí)不能有默認(rèn)參數(shù)值
默認(rèn)情況下产弹,協(xié)議中定義的內(nèi)容必須全部都實(shí)現(xiàn)
35派歌、協(xié)議中的屬性
協(xié)議中定義屬性時(shí)必須用var關(guān)鍵字
實(shí)現(xiàn)協(xié)議時(shí)的屬性權(quán)限要不小于協(xié)議中定義的屬性權(quán)限
協(xié)議定義get、set痰哨,用var存儲(chǔ)屬性或get胶果、set計(jì)算屬性去實(shí)現(xiàn)
協(xié)議定義get,用任何屬性都可以實(shí)現(xiàn)
為了保證通用斤斧,協(xié)議中必須用static定義類型方法稽物、類型屬性、類型下標(biāo)
36折欠、協(xié)議中的init、init?、init!
協(xié)議中還可以定義初始化器init
非final類實(shí)現(xiàn)時(shí)必須加上required
如果從協(xié)議實(shí)現(xiàn)的初始化器锐秦,剛好是重寫了父類的指定初始化器
那么這個(gè)初始化必須同時(shí)加required咪奖、override
協(xié)議中定義的init?、init!酱床,可以用init羊赵、init?、init!去實(shí)現(xiàn)
協(xié)議中定義的init扇谣,可以用init昧捷、init!去實(shí)現(xiàn)
37、CaseIterable
讓枚舉遵守CaseIterable協(xié)議罐寨,可以實(shí)現(xiàn)遍歷枚舉值
38靡挥、CustomStringConvertible
遵守CustomStringConvertible、CustomDebugStringConvertible協(xié)議鸯绿,都可以自定義實(shí)例的打印字符串
print調(diào)用的是CustomStringConvertible協(xié)議的description
debugPrint跋破、po調(diào)用的是CustomDebugStringConvertible協(xié)議的debugDescription
38、Any瓶蝴、AnyObject
Swift提供了2種特殊的類型:Any毒返、AnyObject
Any:可以代表任意類型(枚舉、結(jié)構(gòu)體舷手、類拧簸,也包括函數(shù)類型)
AnyObject:可以代表任意類類型(在協(xié)議后面寫上: AnyObject代表只有類能遵守這個(gè)協(xié)議)
在協(xié)議后面寫上: class也代表只有類能遵守這個(gè)協(xié)議
39、rethrows
rethrows表明:函數(shù)本身不會(huì)拋出錯(cuò)誤男窟,但調(diào)用閉包參數(shù)拋出錯(cuò)誤盆赤,那么它會(huì)將錯(cuò)誤向上拋
40、defer
defer語(yǔ)句:用來(lái)定義以任何方式(拋錯(cuò)誤蝎宇、return等)離開代碼塊前必須要執(zhí)行的代碼
defer語(yǔ)句將延遲至當(dāng)前作用域結(jié)束之前執(zhí)行
defer語(yǔ)句的執(zhí)行順序與定義順序相反
41弟劲、局部作用域
可以使用do 實(shí)現(xiàn)局部作用域
42、關(guān)聯(lián)類型(Associated Type)
關(guān)聯(lián)類型的作用:給協(xié)議中用到的類型定義一個(gè)占位名稱
協(xié)議中可以擁有多個(gè)關(guān)聯(lián)類型
43姥芥、 some
使用some關(guān)鍵字聲明一個(gè)不透明類型
some限制只能返回一種類型
some除了用在返回值類型上兔乞,一般還可以用在屬性類型上
44、運(yùn)算符重載
類凉唐、結(jié)構(gòu)體庸追、枚舉可以為現(xiàn)有的運(yùn)算符提供自定義的實(shí)現(xiàn),這個(gè)操作叫做:運(yùn)算符重載
操作符預(yù)定義 prefix infix postfix
prefix: 運(yùn)算符在運(yùn)算值的前方台囱; postfix:運(yùn)算符在運(yùn)算值的后方淡溯;infix:運(yùn)算符在運(yùn)算值之間
precedencegroup:定義運(yùn)算符的其它屬性
45、Equatable
要想得知2個(gè)實(shí)例是否等價(jià)簿训,一般做法是遵守Equatable 協(xié)議咱娶,重載== 運(yùn)算符
與此同時(shí)米间,等價(jià)于重載了!= 運(yùn)算符
引用類型比較存儲(chǔ)的地址值是否相等(是否引用著同一個(gè)對(duì)象),使用恒等運(yùn)算符=== 膘侮、!==
46屈糊、Comparable
要想比較2個(gè)實(shí)例的大小,一般做法是:
遵守Comparable 協(xié)議
重載相應(yīng)的運(yùn)算符
47琼了、自定義運(yùn)算符(Custom Operator)
可以自定義新的運(yùn)算符:在全局作用域使用operator進(jìn)行聲明
prefix operator 前綴運(yùn)算符
postfix operator 后綴運(yùn)算符
infix operator 中綴運(yùn)算符: 優(yōu)先級(jí)組
precedencegroup 優(yōu)先級(jí)組{
associativity: 結(jié)合性(left\right\none)
higherThan: 比誰(shuí)的優(yōu)先級(jí)高
lowerThan: 比誰(shuí)的優(yōu)先級(jí)低
assignment: true代表在可選鏈操作中擁有跟賦值運(yùn)算符一樣的優(yōu)先級(jí)
}
prefix operator +++
infix operator +- : PlusMinusPrecedence
precedencegroup PlusMinusPrecedence {
associativity: none
higherThan: AdditionPrecedence
lowerThan: MultiplicationPrecedence
assignment: true
}
Apple文檔參考:
https://developer.apple.com/documentation/swift/swift_stadard_library/operator_declarations
https://docs.swift.org/swiftbook/ReferenceManual/Declarations.html#ID380
48逻锐、擴(kuò)展
Swift中的擴(kuò)展,有點(diǎn)類似于OC中的分類(Category)
擴(kuò)展可以為枚舉雕薪、結(jié)構(gòu)體昧诱、類、協(xié)議添加新功能
可以添加方法所袁、計(jì)算屬性盏档、下標(biāo)、(便捷)初始化器纲熏、嵌套類型妆丘、協(xié)議等等
擴(kuò)展不能辦到的事情
不能覆蓋原有的功能
不能添加存儲(chǔ)屬性,不能向已有的屬性添加屬性觀察器
不能添加父類
不能添加指定初始化器局劲,不能添加反初始化器
49勺拣、訪問(wèn)控制(Access Control)
在訪問(wèn)權(quán)限控制這塊,Swift提供了5個(gè)不同的訪問(wèn)級(jí)別(以下是從高到低排列鱼填, 實(shí)體指被訪問(wèn)級(jí)別修飾的內(nèi)容)
open:允許在定義實(shí)體的模塊药有、其他模塊中訪問(wèn),允許其他模塊進(jìn)行繼承苹丸、重寫(open只能用在類愤惰、類成員上)
public:允許在定義實(shí)體的模塊、其他模塊中訪問(wèn)赘理,不允許其他模塊進(jìn)行繼承宦言、重寫
internal:只允許在定義實(shí)體的模塊中訪問(wèn),不允許在其他模塊中訪問(wèn)
fileprivate:只允許在定義實(shí)體的源文件中訪問(wèn)
private:只允許在定義實(shí)體的封閉聲明中訪問(wèn)
絕大部分實(shí)體默認(rèn)都是internal級(jí)別
訪問(wèn)級(jí)別的使用準(zhǔn)則
一個(gè)實(shí)體不可以被更低訪問(wèn)級(jí)別的實(shí)體定義商模,比如
變量\常量類型≥ 變量\常量
參數(shù)類型奠旺、返回值類型≥ 函數(shù)
父類≥ 子類
父協(xié)議≥ 子協(xié)議
原類型≥ typealias
原始值類型、關(guān)聯(lián)值類型≥ 枚舉類型
定義類型A時(shí)用到的其他類型≥ 類型A
元組類型
元組類型的訪問(wèn)級(jí)別是所有成員類型最低的那個(gè)
泛型類型
泛型類型的訪問(wèn)級(jí)別是類型的訪問(wèn)級(jí)別以及所有泛型類型參數(shù)的訪問(wèn)級(jí)別中最低的那個(gè)
成員施流、嵌套類型
類型的訪問(wèn)級(jí)別會(huì)影響成員(屬性响疚、方法、初始化器瞪醋、下標(biāo))忿晕、嵌套類型的默認(rèn)訪問(wèn)級(jí)別
一般情況下,類型為private或fileprivate银受,那么成員\嵌套類型默認(rèn)也是private或fileprivate
一般情況下践盼,類型為internal或public鸦采,那么成員\嵌套類型默認(rèn)是internal
成員的重寫
子類重寫成員的訪問(wèn)級(jí)別必須≥ 子類的訪問(wèn)級(jí)別,或者≥ 父類被重寫成員的訪問(wèn)級(jí)別
父類的成員不能被成員作用域外定義的子類重寫
直接在全局作用域下定義的private等價(jià)于fileprivate
getter咕幻、setter
getter赖淤、setter默認(rèn)自動(dòng)接收它們所屬環(huán)境的訪問(wèn)級(jí)別
可以給setter單獨(dú)設(shè)置一個(gè)比getter更低的訪問(wèn)級(jí)別,用以限制寫的權(quán)限
fileprivate(set) public var num = 10
internal(set) public subscript(index: Int) -> Int { return 0 }
初始化器
如果一個(gè)public類想在另一個(gè)模塊調(diào)用編譯生成的默認(rèn)無(wú)參初始化器谅河,必須顯式提供public的無(wú)參初始化器
因?yàn)閜ublic類的默認(rèn)初始化器是internal級(jí)別
required初始化器≥ 它的默認(rèn)訪問(wèn)級(jí)別
如果結(jié)構(gòu)體有private\fileprivate的存儲(chǔ)實(shí)例屬性,那么它的成員初始化器也是private\fileprivate
否則默認(rèn)就是internal
枚舉類型的case
不能給enum的每個(gè)case單獨(dú)設(shè)置訪問(wèn)級(jí)別
每個(gè)case自動(dòng)接收enum的訪問(wèn)級(jí)別
public enum定義的case也是public
協(xié)議
協(xié)議中定義的要求自動(dòng)接收協(xié)議的訪問(wèn)級(jí)別确丢,不能單獨(dú)設(shè)置訪問(wèn)級(jí)別
public協(xié)議定義的要求也是public
協(xié)議實(shí)現(xiàn)的訪問(wèn)級(jí)別必須≥ 類型的訪問(wèn)級(jí)別绷耍,或者≥ 協(xié)議的訪問(wèn)級(jí)別
擴(kuò)展
如果有顯式設(shè)置擴(kuò)展的訪問(wèn)級(jí)別,擴(kuò)展添加的成員自動(dòng)接收擴(kuò)展的訪問(wèn)級(jí)別
如果沒有顯式設(shè)置擴(kuò)展的訪問(wèn)級(jí)別鲜侥,擴(kuò)展添加的成員的默認(rèn)訪問(wèn)級(jí)別褂始,跟直接在類型中定義的成員一樣
可以單獨(dú)給擴(kuò)展添加的成員設(shè)置訪問(wèn)級(jí)別
不能給用于遵守協(xié)議的擴(kuò)展顯式設(shè)置擴(kuò)展的訪問(wèn)級(jí)別
50、內(nèi)存管理
Swift的ARC中有3種引用
強(qiáng)引用(strong reference):默認(rèn)情況下描函,引用都是強(qiáng)引用
弱引用(weak reference):通過(guò)weak定義弱引用
必須是可選類型的var崎苗,因?yàn)閷?shí)例銷毀后,ARC會(huì)自動(dòng)將弱引用設(shè)置為nil
ARC自動(dòng)給弱引用設(shè)置nil時(shí)舀寓,不會(huì)觸發(fā)屬性觀察器
無(wú)主引用(unowned reference):通過(guò)unowned定義無(wú)主引用
不會(huì)產(chǎn)生強(qiáng)引用胆数,實(shí)例銷毀后仍然存儲(chǔ)著實(shí)例的內(nèi)存地址(類似于OC中unsafe_unretained)
試圖在實(shí)例銷毀后訪問(wèn)無(wú)主引用,會(huì)產(chǎn)生運(yùn)行時(shí)錯(cuò)誤(野指針)
? Fatal error: Attempted to read an unowned reference but object 0x0 was already deallocated
51互墓、weak必尼、unowned的使用限制
weak、unowned只能用在類實(shí)例上面
protocol Livable : AnyObject {}
class Person {}
weak var p0: Person?
weak var p1: AnyObject?
weak var p2: Livable?
unowned var p10: Person?
unowned var p11: AnyObject?
unowned var p12: Livable?
52篡撵、循環(huán)引用(Reference Cycle)
weak判莉、unowned 都能解決循環(huán)引用的問(wèn)題,unowned 要比weak 少一些性能消耗
在生命周期中可能會(huì)變?yōu)閚il 的使用weak
初始化賦值后再也不會(huì)變?yōu)閚il 的使用unowned
53育谬、閉包的循環(huán)引用
如果想在定義閉包屬性的同時(shí)引用self券盅,這個(gè)閉包必須是lazy的(因?yàn)樵趯?shí)例初始化完畢之后才能引用self)
如果lazy屬性是閉包調(diào)用的結(jié)果,那么不用考慮循環(huán)引用的問(wèn)題(因?yàn)殚]包調(diào)用后膛檀,閉包的生命周期就結(jié)束了)
54锰镀、@escaping
非逃逸閉包、逃逸閉包宿刮,一般都是當(dāng)做參數(shù)傳遞給函數(shù)
非逃逸閉包:閉包調(diào)用發(fā)生在函數(shù)結(jié)束前互站,閉包調(diào)用在函數(shù)作用域內(nèi)
逃逸閉包:閉包有可能在函數(shù)結(jié)束后調(diào)用,閉包調(diào)用逃離了函數(shù)的作用域僵缺,需要通過(guò)@escaping聲明
逃逸閉包不可以捕獲inout參數(shù)
55胡桃、指針
Swift中也有專門的指針類型,這些都被定性為“Unsafe”(不安全的)磕潮,常見的有以下4種類型
UnsafePointer<Pointee> 類似于const Pointee *
UnsafeMutablePointer<Pointee> 類似于Pointee *
UnsafeRawPointer 類似于const void *
UnsafeMutableRawPointer 類似于void *
56翠胰、字面量
Swift自帶的絕大部分類型容贝,都支持直接通過(guò)字面量進(jìn)行初始化
Bool、Int之景、Float斤富、Double、String锻狗、Array满力、Dictionary、Set轻纪、Optional等
常見字面量的默認(rèn)類型
public typealias IntegerLiteralType = Int
public typealias FloatLiteralType = Double
public typealias BooleanLiteralType = Bool
public typealias StringLiteralType = String
57油额、字面量協(xié)議
Swift自帶類型之所以能夠通過(guò)字面量初始化,是因?yàn)樗鼈冏袷亓藢?duì)應(yīng)的協(xié)議
Bool : ExpressibleByBooleanLiteral
Int : ExpressibleByIntegerLiteral
Float刻帚、Double : ExpressibleByIntegerLiteral潦嘶、ExpressibleByFloatLiteral
Dictionary : ExpressibleByDictionaryLiteral
String : ExpressibleByStringLiteral
Array、Set : ExpressibleByArrayLiteral
Optional : ExpressibleByNilLiteral
58崇众、模式(Pattern)
什么是模式掂僵?
模式是用于匹配的規(guī)則,比如switch的case顷歌、捕捉錯(cuò)誤的catch锰蓬、if\guard\while\for語(yǔ)句的條件等
Swift中的模式有
通配符模式(Wildcard Pattern)
標(biāo)識(shí)符模式(Identifier Pattern)
值綁定模式(Value-Binding Pattern)
元組模式(Tuple Pattern)
枚舉Case模式(Enumeration Case Pattern)
可選模式(Optional Pattern)
類型轉(zhuǎn)換模式(Type-Casting Pattern)
表達(dá)式模式(Expression Pattern)
59、MARK衙吩、TODO互妓、FIXME
// MARK: 類似于OC中的#pragma mark
// MARK: - 類似于OC中的#pragma mark -
// TODO: 用于標(biāo)記未完成的任務(wù)
// FIXME: 用于標(biāo)記待修復(fù)的問(wèn)題
60、條件編譯
// 操作系統(tǒng):macOS\iOS\tvOS\watchOS\Linux\Android\Windows\FreeBSD
#if os(macOS) || os(iOS)
// CPU架構(gòu):i386\x86_64\arm\arm64
#elseif arch(x86_64) || arch(arm64)
// swift版本
#elseif swift(<5) && swift(>=3)
// 模擬器
#elseif targetEnvironment(simulator)
// 可以導(dǎo)入某模塊
#elseif canImport(Foundation)
#else
#endif
61坤塞、打印
func log<T>(_ msg: T,
file: NSString = #file,
line: Int = #line,
fn: String = #function) {
#if DEBUG
let prefix = "\(file.lastPathComponent)_\(line)_\(fn):"
print(prefix, msg)
#endif
}
62冯勉、dynamic
被@objc dynamic 修飾的內(nèi)容會(huì)具有動(dòng)態(tài)性杏死,比如調(diào)用方法會(huì)走runtime那一套流程
63汰蜘、關(guān)聯(lián)對(duì)象(Associated Object)
在Swift中,class依然可以使用關(guān)聯(lián)對(duì)象
默認(rèn)情況缤骨,extension不可以增加存儲(chǔ)屬性
借助關(guān)聯(lián)對(duì)象浮禾,可以實(shí)現(xiàn)類似extension為class增加存儲(chǔ)屬性的效果
class Person {}
extension Person {
private static var AGE_KEY: Void?
var age: Int {
get {
(objc_getAssociatedObject(self, &Self.AGE_KEY) as? Int) ?? 0
}
set {
objc_setAssociatedObject(self,
&Self.AGE_KEY,
newValue,
.OBJC_ASSOCIATION_ASSIGN)
}
}
}
64交胚、資源名管理
https://github.com/mac-cain13/R.swift
https://github.com/SwiftGen/SwiftGen
65、RxSwift
源碼:https://github.com/ReactiveX/RxSwift
中文文檔: https://beeth0ven.github.io/RxSwift-Chinese-Documentation/
模塊說(shuō)明
RxSwift:Rx標(biāo)準(zhǔn)API的Swift實(shí)現(xiàn)盈电,不包括任何iOS相關(guān)的內(nèi)容
RxCocoa:基于RxSwift蝴簇,給iOS UI控件擴(kuò)展了很多Rx特性
66、Swift
Swift于2015年正式開源匆帚,github地址: https://github.com/apple/swift
標(biāo)準(zhǔn)庫(kù)源碼位置:https://github.com/apple/swift/tree/master/stdlib/public/core
幾個(gè)可能會(huì)經(jīng)嘲敬剩看的目錄
docs:一些文檔
stdlib:Swift源碼
lib:C++源碼
include:C++頭文件
Array分析
map、filter
https://github.com/apple/swift/blob/master/stdlib/public/core/Sequence.swift
flatMap、compactMap互拾、reduce
https://github.com/apple/swift/blob/master/stdlib/public/core/SequenceAlgorithms.swift
Substring分析
append歪今、lowercased、uppercased
https://github.com/apple/swift/blob/master/stdlib/public/core/Substring.swift
Optional分析
map颜矿、flatMap寄猩、==、??
https://github.com/apple/swift/blob/master/stdlib/public/core/Optional.swift
Metadata分析
文檔: https://github.com/apple/swift/blob/master/docs/ABI/TypeMetadata.rst
其他參考
https://github.com/apple/swift/blob/master/include/swift/ABI/Metadata.h
https://github.com/apple/swift/blob/master/include/swift/ABI/MetadataKind.def
https://github.com/apple/swift/blob/master/include/swift/ABI/MetadataValues.h
https://github.com/apple/swift/blob/master/include/swift/Reflection/Records.h