GeekBand~iOS~Swift編程語言~第二周

結(jié)構(gòu)與枚舉

結(jié)構(gòu)

struct屬于值類型,具有值拷貝語義(賦值與傳值)
struct不支持面向?qū)ο螅饕糜诙x輕量級數(shù)值類型;class支持面向?qū)ο螅饕糜谠O(shè)計有豐富關(guān)系的組件系統(tǒng)。
struct有傳參拷貝成本,不要定義尺寸過大的結(jié)構(gòu);class有ARC內(nèi)存管理成本。
不要在struct內(nèi)定義引用類型屬性(會改變struct的值拷貝語義)。

struct VS. class

相同點:
都可以定義以下成員:屬性、方法、下標(biāo)、初始化器
都支持類型擴展、協(xié)議
不同點:
類支持繼承和多態(tài),結(jié)構(gòu)不支持;
類必須自己定義初始化器,結(jié)構(gòu)會有默認的按成員初始化器;
類支持析構(gòu)器,結(jié)構(gòu)不支持;
類的實例在堆上,由ARC負責(zé)釋放;結(jié)構(gòu)的實例在棧上,棧結(jié)束自動釋放,不參與ARC管理
類支持引用相等比較(===與!==),結(jié)構(gòu)不支持

枚舉

enum用于定義一組相關(guān)的值成員,enum同屬于值類型,具有值拷貝語義(賦值與傳參)。
可以使用switch-case語句處理enum,但case必須包含所有的枚舉值,否則需要用default。
可以為enum指定原始值,即raw value,類型可以是字符、字符串、整數(shù)、浮點數(shù)。數(shù)值默認從0開始,字符串與枚舉值名稱相同。
enum支持關(guān)聯(lián)值,可以設(shè)置不同類型的值成員,類似聯(lián)合數(shù)據(jù)結(jié)構(gòu)
enum還可以定義以下成員:計算屬性、方法、初始化器。

繼承與多態(tài)

繼承:子類自動繼承基類的屬性、方法、下標(biāo)。
只有類支持繼承,結(jié)構(gòu)和枚舉不支持繼承。
繼承同時支持實例成員和類成員。
繼承的兩層含義:成員復(fù)用:子類復(fù)用基類成員;類型抽象:將子類當(dāng)作父類來使用(IS-A關(guān)系準(zhǔn)則)

繼承的內(nèi)存模型:


模型.png

多態(tài):子類在同一行為接口下,表現(xiàn)不同的實現(xiàn)方式。
子類使用override關(guān)鍵字來表達多態(tài)定義。
可以重寫的成員有:方法、屬性、下標(biāo);包括實例成員和類型成員。
在子類的代碼中,可以使用super來調(diào)用基類的實現(xiàn)。
在成員上使用final阻止子類override該成員;在類上使用final阻止該類被繼承。

繼承中的init和deinit
初始化器init:
如果子類沒有定義初始化器,則將自動繼承基類的初始化器;
如果子類定義了初始化器,則不再繼承,此時子類初始化器必須調(diào)用基類的一個初始化器。如果手工不調(diào)用,編譯器將自動生成調(diào)用;
如果子類初始化器與基類初始化器原型一致,必須使用override;
在子類中使用基類屬性,必須確保首先調(diào)用基類初始化器
析構(gòu)器deinit
如果子類沒有定義析構(gòu)器,會自動繼承基類析構(gòu)器;
子類析構(gòu)器執(zhí)行完畢后,會自動調(diào)用基類析構(gòu)器(無法手工調(diào)用);
子類析構(gòu)器自動具有多態(tài)性

協(xié)議

協(xié)議:類型的合同約定,只描述外部接口,不提供具體實現(xiàn)。
協(xié)議可以包含以下成員:屬性、方法、初始化器、下標(biāo)、操作符。
一個類型可以實現(xiàn)多個協(xié)議,協(xié)議可以應(yīng)用在如下類型上。但可以添加class關(guān)鍵字標(biāo)明協(xié)議只能應(yīng)用在類上:類、結(jié)構(gòu)、枚舉。

使用協(xié)議:
協(xié)議本質(zhì)上是一種類型,可以作為聲明類型,但不能創(chuàng)建實例。
協(xié)議變量的內(nèi)存模型遵從實際類型的內(nèi)存模型:引用類型傳參、拷貝采用傳引用方式;值類型傳參、拷貝采用傳值方式。
檢查協(xié)議類型:使用is檢查類型是否實現(xiàn)了協(xié)議;使用as?和as!將類型下溯轉(zhuǎn)型為協(xié)議。

協(xié)議中的屬性:
協(xié)議中可以定義只讀屬性,也可以定義讀寫屬性;
協(xié)議中可以定義實例屬性,也可以定義類型屬性;
協(xié)議中只能定義變量屬性,不能定義常量屬性;
實現(xiàn)協(xié)議時,并不要求實現(xiàn)為存儲屬性、還是計算屬性。

協(xié)議中的方法:
協(xié)議可以定義實例方法,也可以定義類型方法;
協(xié)議中的方法不能定義參數(shù)的默認值;
針對值類型的mutating協(xié)議方法:
值類型(struct,enum)實現(xiàn)的實例方法如果要更改實例本身,需要在協(xié)議方法的定義中標(biāo)明mutating關(guān)鍵字,同時在方法實現(xiàn)時也添加mutating關(guān)鍵字。
添加了mutating的協(xié)議方法,對類的實現(xiàn)方法無影響。在類內(nèi)實現(xiàn)mutating協(xié)議方法時,無需再添加mutating關(guān)鍵字。

協(xié)議中的初始化器:
協(xié)議中可以定義初始化器,但不可以定義析構(gòu)器。
當(dāng)class中實現(xiàn)協(xié)議定義的初始化器時,需要添加required關(guān)鍵字:
標(biāo)明子類也需要提供該初始化器;如果定義為final類,則不需要required關(guān)鍵字。
協(xié)議可以定義可失敗的初始化器init?,具體實現(xiàn)時可以失敗、也可以非失敗。

更多協(xié)議形式:
協(xié)議繼承:一個協(xié)議可以繼承一個或多個協(xié)議;實現(xiàn)子協(xié)議的類型,也必須實現(xiàn)父協(xié)議中約定的成員。
協(xié)議組合:
可以使用protocol<A,B,...>來組合多個協(xié)議。
實現(xiàn)組合協(xié)議的類型,必須實現(xiàn)組合協(xié)議中的每一個協(xié)議。
組合協(xié)議是一個臨時類型。
可選協(xié)議:
協(xié)議的某些成員可以定義為optional,不必實現(xiàn);
可選協(xié)議只能應(yīng)用于class,不能應(yīng)用于struct和enum;
可選協(xié)議必須標(biāo)明@objc特性(即使不需要和Objective-C互操作)。

字符串

String是一個Unicode編碼、16位字符的字符序列。
String與NSString支持無縫互操作。
String被定義為struct,值類型,拷貝時具有值語義。
String是一個struct,但內(nèi)部包含一個指向堆上的“內(nèi)容指針”,其指向的對象存放真正的字符串內(nèi)容。

內(nèi)存模型

內(nèi)存模型.png

使用字符串:
使用var和let來控制字符串的可變性;
獲取字符串中的字符;
使用append和+連接字符串;
使用字符轉(zhuǎn)義;
字符串插值(String Interpolation)。

copy-on-write共享技術(shù)
同一個字符串內(nèi)容拷貝到不同的變量中時,“內(nèi)容指針”不變,即不同變量“共享”同一份堆內(nèi)存。從而實現(xiàn)“節(jié)省內(nèi)存”。
如果某一個變量的字符串內(nèi)容改變時,先將原來堆內(nèi)存拷貝一份,“內(nèi)容指針”指向新的拷貝,然后再更改新的拷貝。從而確保“正確性”。
copy-on-write的目的是實現(xiàn)“內(nèi)容相同的字符串共享內(nèi)存,同時又支持字符串隨時改變”。
最佳實踐:盡量不改變字符串,盡量使用常量字符串let。
copy-on-write--更改前

更改前.png

copy-on-write--更改后

更改后.png

緩存容量與增長:
字符串初始化后,會分配一個緩存容量capacity,其長度一般大于實際的字符數(shù)量。
當(dāng)字符串增長時,如果實際需求大于capacity,其capacity會以二倍的方式指數(shù)增長。代價:分配新的堆內(nèi)存 2*capacity;將原來堆內(nèi)存上的內(nèi)容拷貝到新內(nèi)存;釋放原來堆內(nèi)存。
最佳實踐:估計好capacity,預(yù)先分配好一定容量,避免以后capacity的增長。

集合類型

集合類型.png

數(shù)組:
Array是一個有序的元素序列,支持隨機存取,支持動態(tài)更新長度。
索引從0開始,索引訪問越界會拋出運行時異常。
Array被定義為struct,值類型,拷貝時具有值語義。
Array是一個struct,但內(nèi)部包含一個指向堆上的“元素指針”,其指向的對象存放真正的數(shù)組元素。
1.如果數(shù)組元素為值類型,拷貝數(shù)組時,元素包含值本身。
2.如果數(shù)組元素為引用類型,拷貝數(shù)組時,元素引用指向相同的對象。

內(nèi)存模型:

內(nèi)存模型.png

使用數(shù)組:
使用var和let來控制數(shù)組的常量性:數(shù)組長度和元素內(nèi)容都不能更改。
數(shù)組遍歷:使用for循環(huán)訪問array[index]需要檢查索引越界,具有性能代價;盡可能使用for-in遍歷數(shù)組元素;或使用Array.enumerate()遍歷索引;二者編譯器會優(yōu)化掉索引檢查。
盡量避免使用insert和remove操作,因為會改變數(shù)組元素序列,涉及到大量的內(nèi)存拷貝操作,代價較高。

緩存容量與增長
數(shù)組初始化后,會分配一個緩存容量capacity,其長度一般大于實際的元素數(shù)量
當(dāng)數(shù)組長度增長時,如果實際需求大于capacity,其capacity會以近似二倍的方式指數(shù)增長。代價:分配新的堆內(nèi)存 2*capacity;將原來堆內(nèi)存上的內(nèi)容拷貝到新內(nèi)存;釋放原來堆內(nèi)存。
最佳實踐:估計好capacity,預(yù)先分配好一定容量,避免以后capacity的增長。
copy-on-write共享技術(shù)
同一個數(shù)組拷貝到不同的變量中時,“元素指針”不變,即不同變量“共享”同一份堆內(nèi)存。從而實現(xiàn)“節(jié)省內(nèi)存”。
如果某一個變量的元素內(nèi)容改變時,先將原來堆內(nèi)存拷貝一份,“元素指針”指向新的拷貝,然后再更改新的拷貝。從而確保“正確性”。
copy-on-write的目的是實現(xiàn)“元素內(nèi)容相同的數(shù)組共享內(nèi)存,同時又支持元素隨時改變”。
最佳實踐:盡量不改變數(shù)組元素和長度,盡量使用常量數(shù)組。

copy-on-write--更改前

更改前.png

copy-on-write--更改后

更改后.png

集合Set
Set是一個無序的集合,其存儲的值不能重復(fù)。
Set中的元素必須有哈希值,即支持Hashable協(xié)議。
Set被定義為struct,值類型,拷貝時具有值語義。
Set也是一個struct,但內(nèi)部包含一個指向堆上的“元素指針”,其指向的對象存放真正的元素。

字典Dictionary
Dictionary是一個存儲key-value的無序的集合,key唯一,value可重復(fù)。
Dictionary中的key必須有哈希值,即支持Hashable協(xié)議。
Dictionary被定義為struct,值類型,拷貝時具有值語義。
Dictionary也是一個struct,但內(nèi)部包含一個指向堆上的“元素指針”,其指向的對象存放真正的元素。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容