How to Use Copy-on-Write in Swift
What you’ll build or solve
You’ll learn how Copy-on-Write works in Swift and how to implement it manually in a custom struct.
When this approach works best
Copy-on-Write is most useful when:
Learn Swift on Mimo
- You wrap a reference type inside a struct.
- You build performance-sensitive data models.
- You design large value types that are frequently copied.
- You want value semantics with efficient memory usage.
This is less relevant for small data structures where copying cost is negligible.
Prerequisites
- Xcode installed
- Basic Swift syntax
- Understanding of structs vs classes
- Familiarity with value and reference semantics
Swift collections such as Array, Dictionary, and String already use Copy-on-Write automatically.
Example:
varnumbers1= [1,2,3]
varnumbers2=numbers1// Shares storage
numbers2.append(4)// Copy happens here
Assignment alone does not copy memory. Mutation triggers the copy.
You do not manually control this behavior for built-in types.
Step-by-step instructions
Step 1: Understand how Copy-on-Write works
Copy-on-Write combines:
- A value type (struct)
- Internal reference storage (class)
- A uniqueness check before mutation
The struct behaves like a value type. The class stores the actual data.
When you assign the struct, both copies temporarily share the same reference. When one copy mutates, Swift checks if it is uniquely referenced. If not, it creates a new copy before modifying.
Step 2: Implement Copy-on-Write in a custom struct
When you wrap a class inside a struct, you must manually preserve value semantics.
Start with a reference type:
Swift
classStorage {
varvalue:Int
init(value:Int) {
self.value=value
}
}
Now wrap it in a struct:
structCounter {
privatevarstorage:Storage
init(value:Int) {
storage=Storage(value:value)
}
varvalue:Int {
get {storage.value }
set {
if!isKnownUniquelyReferenced(&storage) {
storage=Storage(value:storage.value)
}
storage.value=newValue
}
}
}
Use it:
varcounter1=Counter(value:10)
varcounter2=counter1
counter2.value=20
print(counter1.value)// 10
print(counter2.value)// 20
Without the uniqueness check, both variables would share the same reference.
isKnownUniquelyReferenced checks whether the underlying class instance is shared. If it is shared, you create a new copy before mutation.
What to look for
- Use a private reference type inside the struct.
- Call
isKnownUniquelyReferencedbefore mutation. - Copy storage only when multiple references exist.
- Built-in Swift collections already follow this pattern.
- Reads do not require copying. Only writes do.
Examples you can copy
Example 1: Built-in Array behavior
varlist1= [1,2,3]
varlist2=list1
list2.append(4)
print(list1)// [1, 2, 3]
print(list2)// [1, 2, 3, 4]
Swift performs Copy-on-Write automatically.
Example 2: String behavior
vartext1="Hello"
vartext2=text1
text2+=" World"
print(text1)// Hello
print(text2)// Hello World
Strings also use Copy-on-Write.
Example 3: Custom Copy-on-Write wrapper
vara=Counter(value:5)
varb=a
b.value=100
print(a.value)// 5
print(b.value)// 100
This behaves like a true value type.
Common mistakes and how to fix them
Mistake 1: Forgetting the uniqueness check
What you might do:
storage.value=newValue
Why it breaks:
Two struct instances may share the same reference, violating value semantics.
Correct approach:
if!isKnownUniquelyReferenced(&storage) {
storage=Storage(value:storage.value)
}
storage.value=newValue
Always check before mutating.
Mistake 2: Using a class directly instead of a struct
What you might do:
CSS
classCounter {
varvalue:Int
}
Why it changes behavior:
Classes use shared references by default. Copies affect the same instance.
Correct approach:
Wrap the class inside a struct if you need value semantics with efficient copying.
Troubleshooting
If modifying one variable affects another, verify you are not using a plain class.
If your custom struct still shares state, confirm you used isKnownUniquelyReferenced.
If performance is a concern, profile with Instruments instead of guessing.
If copying happens too often, review where the mutation occurs.
Quick recap
- Swift collections use Copy-on-Write automatically.
- Assignment does not copy memory.
- Mutation triggers copying.
- Custom structs must implement Copy-on-Write manually.
- Use
isKnownUniquelyReferencedbefore mutating shared storage. - Copy-on-Write preserves value semantics efficiently.
Join 35M+ people learning for free on Mimo
4.8 out of 5 across 1M+ reviews
Check us out on Apple AppStore, Google Play Store, and Trustpilot