Difference between value type and a reference type in iOS swift

以下資料皆參考自Ref1,這裡僅作個人學習整理:

  • Definition of Value type and Reference type
  • When do we choose a Value Type over a Reference Type?
  • How Reference and Value types are stored in memory ?

Definition of Value type and Reference type:

Value type definition:

當Value type被assign給變數或傳遞給function時,就會把既有的instance複製一份出去。

Note:

IOS primitive collection types such as array, set, dictionary採用copy-on-write機制,所以只有把前述collection types單純assign給變數或傳遞給function,但未對「值」做修改的話,則新的變數還是指到同一個memory address

Sample code:

struct MyStruct {
    var tmp: Int
}
var a = MyStruct(tmp: 1)
var b = a
print(MemoryAddress(of: &a)) //0x0000000100008398
print(MemoryAddress(of: &b)) //0x00000001000083a0

var arr1 = Array(repeating: 1, count: 9)
var arr2 = arr1
print(MemoryAddress(of: &arr1)) //0x00000001028047a0
print(MemoryAddress(of: &arr2)) //0x00000001028047a0

Reference type definition:

當Reference type被assign給變數或傳遞給function時,只會把reference copy一份給新變數或function,所以新變數仍然指到同一個object。

Sample code:

class MyClass {
    var tmp: Int
    init(_ tmp: Int) {
        self.tmp = tmp
    }
}

var c = MyClass(1)
var d = c
print(MemoryAddress(of: c)) //0x000000010062b930
print(MemoryAddress(of: d)) //0x000000010062b930

When do we choose a Value Type over a Reference Type?

使用Value type時機:

  • 用「 == 」 去比較兩個instance data比較合理時(p.s. double equal operator (aka ==)是用來比較value)
  • 希望新的變數擁有獨立的state
  • Data會在multiple threads中使用,不需要擔心在目前thread上的data會被別的thread修改

使用Reference type時機:

  • 用「 === 」去比較兩個instance比較合理時 (p.s. ===是根據memory address來比較兩個objects是否相同)
  • 你希望產生一個分享且可修改的state

How Reference and Value types are stored in memory ?

  • Value Type — 存在stack上
  • Reference Type — 存在heap上

Note:

Reference type的「reference」是存在stack上,而object instance存在heap上

補充:

The way to prinit struct/class memory address [參考自Ref3]:

struct MemoryAddress<T>: CustomStringConvertible {

    let intValue: Int

    var description: String {
        let length = 2 + 2 * MemoryLayout<UnsafeRawPointer>.size
        return String(format: "%0\(length)p", intValue)
    }

    // for structures
    init(of structPointer: UnsafePointer<T>) {
        intValue = Int(bitPattern: structPointer)
    }
}

extension MemoryAddress where T: AnyObject {

    // for classes
    init(of classInstance: T) {
        intValue = unsafeBitCast(classInstance, to: Int.self)
        // or      Int(bitPattern: Unmanaged<T>.passUnretained(classInstance).toOpaque())
    }
}

Ref:

  1. https://abhimuralidharan.medium.com/difference-between-value-type-and-a-reference-type-in-ios-swift-18cb5145ad7a
  2. https://juejin.cn/post/6844903828274282503
  3. https://stackoverflow.com/questions/24058906/printing-a-variable-memory-address-in-swift