Swift is designed around two core principles: safety and performance.
At first glance, these goals often appear to conflict. Value types provide safety and predictability, but copying large values repeatedly can be expensive. Reference types provide efficiency through shared storage, but they introduce shared mutable state.
Swift solves this tension elegantly through a memory optimization technique called Copy-on-Write (CoW).
If you’ve used Array, Dictionary, Set, or String, you’ve already relied on Copy-on-Write — even if you didn’t realize it.
In this article, we’ll explore:
isKnownUniquelyReferencedensureUnique() preserves value semanticsCopy-on-Write is a strategy where:
A value is only copied when a mutation occurs — not when it is assigned.
This allows multiple variables to share the same underlying storage until one of them attempts to modify it.
Instead of eagerly copying data during assignment, Swift delays copying until mutation is required.
This achieves:
Consider this example:
var numbers = Array(0...1_000_000)
var copy = numbersIf Swift eagerly copied one million integers during assignment, performance would suffer significantly.
Instead:
numbers and copy share the same storage.This lazy copying is the essence of Copy-on-Write.
var a = [1, 2, 3]
var b = aAt this moment:
a and b share the same storage.b.append(4)Now Swift performs a check:
Final result:
a = [1, 2, 3]
b = [1, 2, 3, 4]Value semantics are preserved, but copying only happens when necessary.
Even though Array is a struct, it stores its elements in a hidden reference-type buffer internally.
Before mutating that buffer, Swift performs a runtime check:
isKnownUniquelyReferenced(_:)This function determines whether the underlying storage is exclusively owned.
isKnownUniquelyReferencedThe function signature is:
func isKnownUniquelyReferenced<T: AnyObject>(_ object: inout T) -> BoolIt returns:
true → if exactly one strong reference existsfalse → if multiple strong references existIn practical terms:
“Is this storage exclusively owned?”
If yes → mutate in place.
If no → create a copy first.
inoutYou may wonder why the parameter is marked inout.
This is deliberate and essential.
1. Avoiding Temporary Retains
If the parameter were passed normally, Swift might temporarily increase the reference count while passing it into the function. That temporary retain would falsely indicate the object is not unique.
Using inout prevents that extra reference increment and ensures the check reflects the true ARC count.
2. Enforcing Memory Exclusivity
Swift enforces strict memory access rules. By requiring inout, the compiler guarantees exclusive access to the variable during the check.
This prevents race conditions and overlapping access during mutation.
The name is precise:
isKnownUniquelyReferenced
It does not guarantee uniqueness under every conceivable concurrency scenario. It guarantees uniqueness when Swift can safely prove it under ARC and exclusivity rules.
This is sufficient for implementing Copy-on-Write correctly in standard Swift usage.
To understand the mechanism fully, let’s build our own CoW type.
final class Storage {
var value: Int
init(value: Int) {
self.value = value
}
}We use a final class because:
final avoids dynamic dispatch overhead.struct Counter {
private var storage: Storage
init(value: Int) {
self.storage = Storage(value: value)
}
var value: Int {
get { storage.value }
set {
ensureUnique()
storage.value = newValue
}
}
}Externally, Counter behaves like a value type.
Internally, it shares reference storage.
ensureUnique()extension Counter {
private mutating func ensureUnique() {
if !isKnownUniquelyReferenced(&storage) {
storage = Storage(value: storage.value)
}
}
}This function guarantees:
Before mutation occurs, the struct owns its storage exclusively.
ensureUnique() Is mutatingIf the storage is shared, we assign a new instance to storage. That modifies self, so the method must be marked mutating.
ensureUnique() Actually DoesIt does not mutate the value directly.
It only ensures that mutation can occur safely.
Think of it as a safety checkpoint before modification.
Consider:
var a = Counter(value: 10)
var b = a
b.value = 20a ──┐
├── Storage(value: 10)
b ──┘Reference count = 2.
b.value = 20 calls:
ensureUnique()Swift checks:
isKnownUniquelyReferenced(&storage)Result: false
storage = Storage(value: storage.value)Now each instance has its own storage.
storage.value = 20Final state:
a.value // 10
b.value // 20Value semantics preserved.
If you skipped ensureUnique():
storage.value = newValueYou would accidentally mutate shared storage.
Your struct would behave like a class.
Value semantics would be broken silently.
The uniqueness check is what guarantees correctness.
The uniqueness check:
Copy-on-Write performs best when:
However, repeated copying inside tight mutation loops can reduce performance.
Understanding this helps you design more efficient systems.
Copy-on-Write gives Swift the best of both worlds:
| Feature | Struct + CoW | Class |
|---|---|---|
| Value semantics | ✅ | ❌ |
| Shared storage | ✅ | ✅ |
| Predictable behavior | ✅ | ❌ |
| Memory efficiency | ✅ | ✅ |
It enables:
When implementing Copy-on-Write:
final class for storage.These rules are non-negotiable.
Copy-on-Write is not just a performance trick. It is a foundational design pattern in Swift.
It allows Swift to deliver:
The partnership between:
isKnownUniquelyReferencedensureUnique()is what makes Swift’s standard library both elegant and powerful.
Mastering Copy-on-Write deepens your understanding of how Swift balances safety with efficiency — and equips you to design high-performance abstractions in your own code.
Thank you for reading. If you have any questions, feel free to follow me on X and send me a DM. If you enjoyed this article and would like to support my work, Buy me a coffee ☕️