Copy-on-write

Swift language Mid-level Swift 5.0+ iOS 17+ Reviewed By Alok Singh

Predict the output

When is the array's storage actually copied?

var a = [1, 2, 3]
var b = a
b.append(4)
print(a.count, b.count)
Options
Hint 1 of 1

What triggers the copy?

Choose an answer, then open Show answer below to check it.

Show answer

Answer: B At b.append(4)

Correct. The first write to a shared buffer makes b copy it; this prints 3 4.

Why not the others?
  • A At var b = a. Assignment shares the buffer; nothing is copied yet.
  • C Never, both share one buffer. Then a would see the append; a still has 3 elements.
  • D At print. Reading doesn't copy.

30-second answer

Copy-on-write lets value types like Array, Dictionary and String share one buffer between copies until one of them is modified. Assigning is cheap; the real copy happens on the first write to a shared buffer. Your own structs get this only if you implement it with isKnownUniquelyReferenced.

Practise saying it · 30 s. No recording, just a timer

Explain copy-on-write.

Say your answer out loud, then check which of these points you covered:

  • Shared buffer until a write
  • Standard collections use it
  • isKnownUniquelyReferenced for your own types

Deep dive

Large structs without CoW are copied field by field, which is usually fine.

Mutating inside a loop on a shared array triggers one copy, not one per iteration.

Implement CoW with a private class storage and isKnownUniquelyReferenced(&storage) before writes.

Passing arrays to functions doesn't copy unless the function mutates a local var copy.

Common mistakes

  • Thinking var b = a copies the array immediately.
  • Assuming custom structs get CoW automatically.

Senior take & follow-ups

Seniors can sketch a CoW implementation.

Follow-up questions

Think of your answer first, then open the hint.

  1. How do you implement CoW?

    Show hint

    Class storage plus isKnownUniquelyReferenced.

  2. Is CoW thread-safe?

    Show hint

    The uniqueness check is, but the buffer must not be mutated from two threads.

Suggest a fix if something here is wrong or out of date.