Understanding Copy-on-Write in Swift?

How can we implement this in iOS development?

Image for post
Image for post

There may be a cost to copying large arrays or dictionaries. Luckily Swift implements Copy-on-Write to avoid copying the whole array (or dictionary) every time it is passed as an argument, saving resources.

Prerequisites:

  • Variables

Terminology

Classes: A construct that defines properties and methods to add functionality to the basic building blocks of Swift code. Classes are reference types.

Copy on write: A common technique to help boost performance while copying structures. In Swift this technique is implemented on both arrays and dictionaries.

Structs: A construct that defines properties and methods to add functionality to the basic building blocks of Swift code. Structs are value types.

Deep copy and shallow copy: Value types are deep copy, that is they copy everything. Reference types employ a shallow copy, so any object pointed to by the source is also pointed to by the destination.

Simple diagrams

Image for post
Image for post
Classes as reference types
Image for post
Image for post
Structs as value types

Copying value types

When value types are copied (as in the “Structs as value types” diagram above) the effect is that an independent instance is created with a unique copy of the data.

Copy-on-Write

When two variables refer to the same array they both point to the same underlying data, contrary to the usual semantics for value types. Because of this contradiction we have to copy back any modifications to the underlying data, Swift takes a copy (at and only at this point) so only the variable that is being used is modified.

Essentially there is a delay to the copy operation until the variable is actually needed, a good optimisation when large arrays or dictionaries are copied.

The value type variable is only copied when we make a change. Before this it is treated as a reference type, as a resource that is duplicated and not modified does NOT require a new resource.

By employing this technique (also known as implicit sharing or shadowing) less resources are consumed by unmodified copies.

Swift’s copy-on-write

Swift implements copy-on-write for Arrays and Dictionaries. However you should be aware that you don’t get it for free in your own data types and if you want this functionality you would need to implement it yourself!

Wait, what? Give me an example with code.

Here is a demonstration of what is happening in Swift under the hood.

When we copy an array, at first there is no change in the location.

As soon as a change is made, the location changes (array1 and array2 are now pointing towards different memory locations).

So, a full example

We are going to create a restaurant system, where a number of people can split a bill equally between them.

So James and Kim

let people = [“James”, “Kim”]

Sit at table number 1

let table1 = Table(tableno: 1, people: people )

The table class (and it must be a reference type as this technique is for the deep storage of value types)

Creating the bill is reasonably simple, but there is one kink in this

The belongsTo var must be set as a new instance to the table, rather than passes as a reference — if not it would forever be linked to the created table outside the class.

The Apple documentation for isKnownUniquelyReferenced(_:) https://developer.apple.com/documentation/swift/2429905-isknownuniquelyreferenced gives us a way fowards (as the documentations says, “useful for implementing the copy-on-write optimization for the deep storage of value types:”)

This means we can implement a private computed var

And here we know if isKnownUniquelyReferenced is called we create a copy of the table.

Want a full GitHub swift file? Ok

Want to get in contact? Try the link here:

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store