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.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Reference vs. Value Types in Swift
30 mins
- Getting Started
- Reference Types vs. Value Types
- Reference Types
- Value Types
- Mutability
- What Type Does Swift Favor?
- Which to Use and When
- When to Use a Value Type
- When to Use a Reference Type
- Still Undecided?
- Mixing Value and Reference Types
- Reference Types Containing Value Type Properties
- Value Types Containing Reference Type Properties
- Getting Value Semantics From Mixed Types
- Copying References During Initialization
- Using Copy-on-Write Computed Properties
- Defensive Mutating Methods
- A More Efficient Copy-on-Write
- Where to Go From Here?
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.
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.
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.
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 struct
s.
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.