Understanding reference vs. value types in Objective-C and Swift

Robots & Pencils
RoboPress
Published in
4 min readDec 3, 2015

--

To cross the divide from Objective-C to Swift, you’ll need a rock-solid understanding of the differences in how these two languages distinguish between reference types and value types. As you continue on your quest to become a master of Swift, here are some detailed definitions, hints and examples to help you along!

In Objective-C, compound data types are represented using @class instances, which are handled using reference semantics. This means that when an instance is assigned or passed as a parameter to a function, the memory allocation represented by the object instance is not copied or duplicated, and can be changed, or mutated, by operations performed on any reference to the instance.

For example, assume a class of type SimpleNumber, which has a single integer property, count:

After the last line has executed, what will be the value of a.count? The answer is 2, because the instances a and b both refer to the same allocation of memory. As far as the allocated memory is concerned, changing b has the same effect as changing a.

With Swift, object types can be divided into two general categories, according to whether they observe reference or value conventions. An object of the class type is treated as a reference in assignments and when passed as a parameter, just like the @class behaves in Objective-C. Fundamental types, such as integers and floating point values, are considered to be value types. Advanced language types such as String, Array and all Collections are implemented as structs, rather than classes, as they are in Objective-C.

In Swift, the struct is another kind of compound data type. The Swift struct is syntactically similar to the class, in that they can also be declared to have properties and methods and is a first-class object type in its own right. However, it differs in that structs are treated as being a value type. In any assignment or parameter creation involving a struct, the instance is automatically copied‡, resulting in two allocations of the data contained in the struct instance.

Consider this example of using a Swift struct:

What value does a.count have after the last line executes? Unlike the previous example, it is not 2 — this time, it is still 1! This occurs because of the copy operation that took place when b was declared and assigned the value of a.

If you’re caught unaware, this important difference between classes and structs in Swift can easily cause unintended behaviors. If you declare a struct where you expected reference type behavior, your code may work in ways you didn’t anticipate.

Here’s an example:

Assume you declare a data class as a struct

And then, later on in your program, you decide to iterate over an array of Students, because you would like to modify them.

Do you see the problem? The Student items will not change because of this line:

This instruction makes a copy of the Student item in the Students array, and even though we change the properties in the copied item, because it is a copy, the original Student item in the array remains unchanged!

To achieve the behavior you want, you could re-declare Student as a class type. Then since class instances are handled using reference semantics, the changes to the Student items will take effect as originally intended.

‡ Technically, it is not copied until the original or the copy are modified, as Swift memory management uses a copy-on-write strategy to optimize memory allocations of value types.

--

--

A digital innovation firm. We help our clients use mobile, web & frontier technologies to transform their businesses and create what’s next.