Swift中值類型、引用類型:Struct 與Class區(qū)別與應(yīng)用

Swift 中Class和Struct異同

Swift 中類和結(jié)構(gòu)體有很多共同點(diǎn)。共同處在于:

  • 定義屬性用于存儲值
  • 定義方法用于提供功能
  • 定義下標(biāo)操作使得可以通過下標(biāo)語法來訪問實(shí)例所包含的值
  • 定義構(gòu)造器用于生成初始化值
  • 通過擴(kuò)展以增加默認(rèn)實(shí)現(xiàn)的功能
  • 實(shí)現(xiàn)協(xié)議以提供某種標(biāo)準(zhǔn)功能

與結(jié)構(gòu)體相比,類還有如下的附加功能:

  • 繼承允許一個(gè)類繼承另一個(gè)類的特征
  • 類型轉(zhuǎn)換允許在運(yùn)行時(shí)檢查和解釋一個(gè)類實(shí)例的類型
  • 析構(gòu)器允許一個(gè)類實(shí)例釋放任何其所被分配的資源
  • 引用計(jì)數(shù)允許對一個(gè)類的多次引用

Tip: 類的對象是引用類型,而結(jié)構(gòu)體是值類型。所以類的賦值是傳遞引用,結(jié)構(gòu)體則是Copy傳值,不是使用引用計(jì)數(shù)。
類為支持的額外功能會增加其復(fù)雜性。一般,更傾向使用選擇結(jié)構(gòu)和枚舉,因?yàn)樗麄兏菀桌斫?而類,則當(dāng)再在合適和必要的時(shí)候使用。實(shí)際上,這意味著大多數(shù)的自定義數(shù)據(jù)類型定義為結(jié)構(gòu)和枚舉就可以了。


值類型、引用類型 最基本的定義:

值類型每個(gè)實(shí)例都擁有其數(shù)據(jù)的一份副本。當(dāng)被賦值給一個(gè)變量或常量,或傳遞給一個(gè)函數(shù)時(shí)候,它會建立一份新的副本。

引用類型所有實(shí)例共享一個(gè)數(shù)據(jù)副本。當(dāng)被賦值給一個(gè)變量或常量,或傳遞給一個(gè)函數(shù)時(shí)候,一個(gè)引用類型一旦被初始化,會返回一個(gè)指向已存在實(shí)例的引用。

比較項(xiàng) struct class
類型 值類型 引用類型
屬性初始化 可用默認(rèn)構(gòu)造直接初始化 需要自己創(chuàng)建構(gòu)造方法
變量賦值 深拷貝 淺拷貝,增加原對象引用
方法中修改屬性 需要添加mutating 不需要
繼承關(guān)系 不能繼承 可以繼承
內(nèi)存 棧上,自動內(nèi)存管理 堆上,手動內(nèi)存管理
速度 高效 相比效率低
線程安全 自動線程安全的 大多是非線程安全的
與oc混編 不支持,oc無法調(diào)struct 支持混編
序列化 不支持,可用字節(jié)轉(zhuǎn)NSData 支持序列化

Class優(yōu)勢 Struct

  • 混合開發(fā)中,OC無法調(diào)用swift的struct,因?yàn)閛c調(diào)用swift代碼,對象必須繼承nsobject
  • struct不能相互繼承,
  • struct不能被序列化成NSdata對象,所以不能存入NSUserDefaults,所以需要數(shù)據(jù)序列化,儲存最好用class實(shí)現(xiàn)

struct的優(yōu)點(diǎn)

  • 安全性:Struct是值類型傳遞,沒有引用計(jì)數(shù)
  • 內(nèi)存:由于他沒有引用計(jì)數(shù),不會因?yàn)檠h(huán)引動導(dǎo)致內(nèi)存泄露
  • 速度:Struct 值類型通常是以棧分配,不是堆,所以Struct比class快的多
  • 拷貝:當(dāng)你拷貝一個(gè)對象時(shí)不需要知道是深拷貝,淺拷貝
  • 線程安全:無論從那個(gè)線程訪問Struct,都簡單

總結(jié):
各有優(yōu)缺點(diǎn),如果模型較小,無需繼承和存儲到NSUserDefaults,或無需oc使用時(shí),可以用Struct。
struct可以保證代碼更加安全可靠,以及struct+protocol更加切合swift面向協(xié)議編程的初衷

二、struct并不是swift中唯一的值類型,class也不是唯一的引用類型。下面是一些例子:

值類型 引用類型
Int Function
Double Closures
String NSString
Array NSArray
Dictionary NSDictionary
Set NSSet
Struct Class
Enum NS 繼承NSObject相關(guān)數(shù)據(jù)類型
Tuple

備注:Swift把一個(gè)引用類型看成一個(gè)類,這和Objective-C中很像。Objective-C中一切繼承于NSObject都被按照引用類型存儲

三、我們什么時(shí)候選擇值類型而不用引用類型?

以下時(shí)候使用值類型:

  • 想要用==比較實(shí)例數(shù)據(jù)。一個(gè)雙等號(==)用于比較值。

  • 你想復(fù)制來建立獨(dú)立數(shù)據(jù)。

  • 數(shù)據(jù)要在多線程的代碼中使用,那么你就不用擔(dān)心數(shù)據(jù)會被其他線程改變。

以下時(shí)候使用引用類型(比如一個(gè)類):

  • 想要用===比較實(shí)例一致性。===會檢查兩個(gè)對象是否完全一致,包括存儲數(shù)據(jù)的內(nèi)存地址。

  • 你想要創(chuàng)建用于共享,可改變的數(shù)據(jù)。

引用類型和值類型在內(nèi)存中怎么存儲?

  • 值類型-在棧內(nèi)存中存儲
  • 引用類型-在托管堆內(nèi)存中存儲

棧與堆的不同!

像前面說的,引用類型實(shí)例存在堆中,值類型實(shí)例比如結(jié)構(gòu)存在于一個(gè)稱為棧的內(nèi)存區(qū)域中。如果值類型實(shí)例是一個(gè)類的一部分,值會和類一起存在堆中。

棧被用于靜態(tài)存儲分配,棧用于動態(tài)存儲分配,它們都存在計(jì)算機(jī)的RAM中。

棧被CPU緊密管理并優(yōu)化,當(dāng)一個(gè)函數(shù)創(chuàng)建一個(gè)變量,棧會存儲這個(gè)變量,并在函數(shù)退出時(shí)候被毀掉。被分配到棧的變量直接存儲在內(nèi)存上,訪問這段內(nèi)存非??臁.?dāng)一個(gè)函數(shù)或者方法調(diào)用另一個(gè)函數(shù),另一個(gè)函數(shù)再依次調(diào)用其他函數(shù)等等,直到最后一個(gè)函數(shù)返回它的值之前,其他所有函數(shù)都會保持暫停執(zhí)行。

棧總是按照LIFO順序保留,最新保留的區(qū)塊總是會下一個(gè)釋放。這使得跟蹤記錄棧非常簡單,釋放一個(gè)棧上的區(qū)塊不過是調(diào)整一個(gè)指針。因?yàn)闂7浅=M織有序,所以它快捷高效。

系統(tǒng)使用堆存儲被其他對象引用的數(shù)據(jù),堆是一大片內(nèi)存,系統(tǒng)可以從中請求并動態(tài)分配內(nèi)存區(qū)塊。堆并不會像棧一樣自動毀掉它的對象,需要外部工作來處理這些。在蘋果設(shè)備中ARC就做這個(gè)工作。引用數(shù)量會被ARC追蹤,當(dāng)它變?yōu)?時(shí)對象會被釋放。因此整個(gè)過程(分配,追蹤引用,釋放)會比棧要慢。所以值類型要快于引用類型。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容