Swift Value Semantics & COW

Swift Value Semantics & COW

Understanding how Swift manages data in memory is crucial for writing efficient, bug-free applications.

Swift heavily favors Value Semantics over Reference Semantics.

This fundamental choice dictates how variables behave when they are assigned to new variables or passed into functions.


Reference Types (Classes)

Classes are reference types. When you assign a class object to a new variable, it does not copy the object.

Instead, both variables point to the exact same location in memory. Modifying one will modify the other!

Reference Semantics Example:

class SharedData { var value = 10 }

let refA = SharedData() let refB = refA // Both point to the same memory

refB.value = 50 print(refA.value) // Outputs 50! refA was modified!


Value Types (Structs and Enums)

Structs, Enums, and basic types (like Int, String, Array) are value types.

When you assign a value type to a new variable, Swift creates an entirely separate copy of the data. Modifying the new copy does not affect the original.

Value Semantics Example:

struct UniqueData { var value = 10 }

var valA = UniqueData() var valB = valA // A complete copy is made!

valB.value = 50 print(valA.value) // Outputs 10. valA is safe and untouched!

This makes structs incredibly safe. You never have to worry about another part of your program silently altering your data behind your back.


Copy-On-Write (COW)

You might be thinking: "Wait, if arrays are value types, isn't it horribly inefficient to copy a 10,000-element array every time I assign it to a new variable?"

The answer is yes. That's why Swift implements an optimization called Copy-On-Write (COW) for its large collections.

When you assign an array to a new variable, Swift initially acts like a reference type. Both variables point to the same data to save memory.

However, the exact moment you try to mutate (modify) one of those variables, Swift intercepts the action, quickly duplicates the memory under the hood, and applies the change solely to the copy!

Copy-On-Write Concept:

var array1 = [1, 2, 3]
var array2 = array1 // No memory copied yet. Fast!

array2.append(4) // Memory is duplicated RIGHT HERE, then mutated. print(array1) // [1, 2, 3]

Because of COW, Swift developers get the incredible safety of value types, alongside the memory efficiency of reference types!


Exercise

When does Swift actually duplicate the memory for a Copy-On-Write type like an Array?