Swift 淺談Struct與Class


討論Struct與Class之前,我們先來看一個概念:Value Type(值類型)Reference Type(引用類型)

1. 值類型的變量直接包含他們的數據,對於值類型都有他們自己的數據副本,因此對一個變量操作不可能影響另一個變量;

2. 引用類型的變量存儲對他們的數據引用,因此后者稱為對象,因此對一個變量操作可能影響另一個變量所引用的對象。

這就是我們之前博客中提到的深拷貝與淺拷貝,博客傳送《iOS 圖文並茂的帶你了解深拷貝與淺拷貝》,兩者的本質區別在於:深拷貝就是內容拷貝,淺拷貝就是指針拷貝

      A. 是否開啟新的內存地址

      B. 是否影響內存地址的引用計數

 

討論Struct與Class之前,我們先做好准備工作,首先分別創建一個Struct:【SNode】 與 Class:【CNode】

struct SNode {
    var Data: Int?
}
class CNode {
    var Data: Int?
}

下面我們通過代碼來理解兩者都有哪些異同: 

1、property初始化的不同

let snode = SNode(Data: 4) // struct可直接在構造函數中初始化property
print("snode.data:\(String(describing: snode.Data))")


let cnode
= CNode() // class不可直接在構造函數中初始化property
cnode.Data = 5
print("cnode.data:\(String(describing: cnode.Data))")

     打印結果:

snode.data:Optional(4)
cnode.data:Optional(5)

     主要的差別就是 class 在初始化時不能直接把 property 放在 默認的constructor 的參數里,而是需要自己創建一個帶參數的constructor, 如:

class CNode {
    var Data: Int?

    init(data: Int) {
        self.Data = data
    }
}
let cnode = CNode.init(data: 5)

 

2、變量賦值方式不同(深淺copy)

// struct
let snode = SNode(Data: 4) var snode1 = snode snode1.Data = 5 print("snode.data:\(String(describing: snode.Data))\n snode1.data:\(String(describing: snode1.Data))")

    打印結果:

snode.data:Optional(4)
snode1.data:Optional(5)

    說明:struct 賦值“=”的時候,會copy一份完整相同的內容給另一個變量 --> 【開辟了新的內存地址】

// class
let cnode = CNode()
cnode.Data = 5
let cnode1 = cnode
cnode1.Data = 6
print("cnode.data:\(String(describing: cnode.Data))\n cnode1.data:\(String(describing: cnode.Data))")

    打印結果:

cnode.data:6
cnode1.data:6

    說明:class 賦值“=”的時候,不會copy一份完整的內容給另一個變量,只是增加了原變量內存地址的引用而已 --> 【沒有開辟了新的內存地址】

 

3、immutable 變量

     Swift 語言的特色之一就是可變動內容和不可變內容用 var 和 let 來甄別,如果初始為let的變量再去修改會發生編譯錯誤。

     struct也遵循這一特性

     class不存在這樣的問題:從上面的賦值代碼能很清楚的看出來。

 

4、mutating function

struct SNode {
    var Data: Int
}

extension SNode {
    mutating func changeData(vaule: Int) {
        self.Data = vaule
    }
}
class CNode {
    var Data: Int = 0
}

extension CNode {
    func changeData(vaule: Int) {
        self.Data = vaule
    }
}

     說明:struct 和 class 的差別是 struct 的 function 要去改變 property 的值的時候要加上 mutating,而 class 不用

 

5、繼承

     struct不能繼承,class可以繼承。

 

6、struct比class更“輕量級”

     struct分配在棧中,class分配在堆中。

 

題外話:Swift 把 Struct 作為數據模型的注意事項

   優點:

   1、安全性:

因為 Struct 是用值類型傳遞的,它們沒有引用計數。

   2、內存:

由於他們沒有引用數,他們不會因為循環引用導致內存泄漏。

   3、速度:

 值類型通常來說是以棧的形式分配的,而不是用堆。因此他們比 Class 要快很多!  (http://stackoverflow.com/a/24243626/596821)

   4、拷貝:

 Objective-C 里拷貝一個對象,你必須選用正確的拷貝類型(深拷貝、淺拷貝),而值類型的拷貝則非常輕松!

   5、線程安全

值類型是自動線程安全的。無論你從哪個線程去訪問你的 Struct ,都非常簡單。

 

   缺點:

   1、Objective-C

當你的項目的代碼是 Swift 和 Objective-C 混合開發時,你會發現在 Objective-C 的代碼里無法調用 Swift 的 Struct。因為要在 Objective-C 里調用 Swift 代碼的話,對象需要繼承於 NSObject。
Struct 不是 Objective-C 的好朋友。

   2、繼承

Struct 不能相互繼承。

   3、NSUserDefaults

Struct 不能被序列化成 NSData 對象。

 

所以:如果模型較小,並且無需繼承、無需儲存到 NSUserDefault 或者無需 Objective-C 使用時,建議使用 Struct。

 

知識延伸:為什么訪問struct比class快?

“堆”和“棧”並不是數據結構上的Heap跟Stack,而是程序運行中的不同內存空間。棧是程序啟動的時候,系統事先分配的,使用過程中,系統不干預;堆是用的時候才向系統申請的,用完了需要交還,這個申請和交還的過程開銷相對就比較大了。

棧是編譯時分配空間,而堆是動態分配(運行時分配空間),所以棧的速度快。

從兩方面來考慮:

      1.分配和釋放:堆在分配和釋放時都要調用函數(MALLOC,FREE),比如分配時會到堆空間去尋找足夠大小的空間(因為多次分配釋放后會造成空洞),這些都會花費一定的時間,而棧卻不需要這些。

      2.訪問時間:訪問堆的一個具體單元,需要兩次訪問內存,第一次得取得指針,第二次才是真正得數據,而棧只需訪問一次。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM