Reference vs. Value Types in Swift

Learn the subtle, but important, differences between reference and value types in Swift by working through a real-world problem. By Adam Rush.

Leave a rating/review
Download materials
Save for later
Share
Update note: Adam Rush updated this tutorial to iOS 12, Xcode 10, and Swift 4.2. Eric Cerney wrote the original tutorial.

If you’ve been keeping up with the sessions from recent WWDCs, you might have noticed a real emphasis on rethinking code architecture in Swift. One of the biggest differences developers note when coming to Swift from Objective-C is a heavy preference for value types over reference types.

In this tutorial, you’ll learn:

  • Key concepts of value and reference types
  • Differences between the two types
  • How to choose which to use

You’ll work through a real-world problem as you learn about the main concepts of each type. Additionally, you’ll learn more advanced concepts and discover some subtle, but important, points about both types.

Whether you’re coming from an Objective-C background, or you’re more versed in Swift, you’re sure to learn something about the ins and outs of typing in Swift.

Getting Started

First, create a new playground. In Xcode, select File ‣ New ‣ Playground… and name the playground ReferenceTypes.

Note: You can select any platform since this tutorial is platform-agnostic and only focuses on the Swift language aspects.

Click Next, choose a convenient location to save the playground and click Create to open it.

Reference Types vs. Value Types

So, what’s the core difference between these two types? The quick and dirty explanation is that reference types share a single copy of their data while value types keep a unique copy of their data.

Swift represents a reference type as a class. This is similar to Objective-C, where everything that inherits from NSObject is stored as a reference type.

There are many kinds of value types in Swift, such as struct, enum, and tuples. You might not realize that Objective-C also uses value types in number literals like NSInteger or even C structures like CGPoint.

To better understand the difference between the two, it’s best to start out with what you may recognize from Objective-C: reference types.

Reference Types

Reference types consist of shared instances that can be passed around and referenced by multiple variables. This is best illustrated with an example.

Add the following to your playground:

// Reference Types:

class Dog {
  var wasFed = false
}

The above class represents a pet dog and whether or not the dog has been fed. Create a new instance of your Dog class by adding the following:

let dog = Dog()

This simply points to a location in memory that stores dog. To add another object to hold a reference to the same dog, add the following:

let puppy = dog

Because dog is a reference to a memory address, puppy points to the exact same data in memory. Feed your pet by setting wasFed to true:

puppy.wasFed = true

puppy and dog both point to the exact same memory address.

value-reference

Therefore you’d expect any change in one to be reflected in the other. Check that this is true by viewing the property values in your playground:

dog.wasFed     // true
puppy.wasFed   // true

Changing one named instance affects the other since they both reference the same object. This is exactly what you’d expect in Objective-C.

Value Types

Value types are referenced completely differently than reference types. You’ll explore this with some simple Swift primitives.

Add the following Int variable assignments and the corresponding operations to your playground:

// Value Types:

var a = 42
var b = a
b += 1

a    // 42
b    // 43

What would you expect a and b to equal? Clearly, a equals 42 and b equals 43. If you’d declared them as reference types instead, both a and b would equal 43 since both would point to the same memory address.

The same holds true for any other value type. In your playground, implement the following Cat struct:

struct Cat {
  var wasFed = false
}

var cat = Cat()
var kitty = cat
kitty.wasFed = true

cat.wasFed        // false
kitty.wasFed      // true

This shows a subtle, but important, difference between reference and value types: Setting kitty’s wasFed property has no effect on cat. The kitty variable received a copy of the value of cat instead of a reference.

value-value

Looks like your cat’s going hungry tonight! :]

Although it’s much faster to assign a reference to a variable, copies are almost as cheap. Copy operations run in constant O(n) time since they use a fixed number of reference-counting operations based on the size of the data. Later on in this tutorial, you’ll see the clever methods in Swift that optimize these copy operations.

Mutability

var and let function differently for reference types and value types. Notice that you defined dog and puppy as constants with let, yet you were able to change the wasFed property. How’s that possible?

For reference types, let means the reference must remain constant. In other words, you can’t change the instance the constant references, but you can mutate the instance itself.

For value types, let means the instance must remain constant. No properties of the instance will ever change, regardless of whether the property is declared with let or var.

It’s much easier to control mutability with value types. To achieve the same immutability and mutability behaviors with reference types, you’d need to implement immutable and mutable class variants such as NSString and NSMutableString.

What Type Does Swift Favor?

It may surprise you that the Swift standard library uses value types almost exclusively. The results of a quick search through the Swift Standard Library for public instances of enum, struct, and class in Swift 1.2, 2.0, and 3.0 show a bias in the direction of value types:

Swift 1.2:

  • struct: 81
  • enum: 8
  • class: 3

Swift 2.0:

  • struct: 87
  • enum: 8
  • class: 4

Swift 3.0:

  • struct: 124
  • enum: 19
  • class: 3

This includes types like String, Array, and Dictionary, which are all implemented as structs.

Which to Use and When

Now that you know the difference between the two types, when should you choose one over the other?

One situation leaves you no choice. Many Cocoa APIs require NSObject subclasses, which forces you into using class. Other than that, you can use the cases from Apple’s Swift blog under How to Choose? to decide whether to use a struct or enum value type or a class reference type. You’ll take a closer look at these cases in the following sections.