A Swift Guide on Value and Reference Types

Value and Reference types in Swift define how a variable can be passed around in code, whether directly or by making copies of the data. Their usage can greatly impact how you organize and write code.

Value Types

A value type is immutable and cannot be edited once it is set. Any changes to a variable result in a new instance of that value type. This may seem counter-intuitive if we use a variable such as var i = 10, since vars are meant to be mutable, but in reality, we are creating a new in-memory instance every time that we update that variable.

“The most basic distinguishing feature of a value type is that copying — the effect of assignment, initialization, and argument passing — creates an independent instance with its own unique copy of its data” — Swift Blog

Consider the following code:

var testScore: Int = 80
var studentA.testResults = testScore
testScore = 90

If we read out Student A’s test results, we’ll expect him or her to have a score of 80. That’s because the variable studentA.testResultsis set with a copy of testScore in memory, but not the actual instance of testScore. Any changes to a value type after assigning it to a variable do not affect that variable. An Integer, like testScore, uses value semantics to achieve this result.

Reference Types

Reference Types are shared instances of an object that are passed around directly in code. When it is copied from one variable to another, both access the same instance and data. Therefore, a change to one will affect the other.

class TestResults {var score: Int?}
var results = TestResults()
var studentA.testResults = results
var studentB.testResults = results
studentA.testResults.score = 95
studentB.testResults.score = 75

If we read out the test scores, both students will have a test score of 75! This is because classes are built with reference semantics. Student A’s test results references the same results variable as Student B’s, so when we update the score to 75, both students get the new grade.

Inversely, if TestResults was a struct instead of a class, then value semantics are at play and Student A’s test results would have stayed at a 95. That’s because a copy of results would have been made each time it was saved to a new variable.

Differentiating the Two

Reference types are created with classes while value types are typically created with a struct, enum, tuple, or even a primitive type (such as String, Int, Double, …). Arrays and Dictionaries are also examples of value types.

Comparing the Two

When you are comparing the equality of two value types, you will typically just use ==. When you working with two reference types, you have an option. If you want to verify that two instances are the same instance, you’ll use ===, but if you want to compare two separate instances for equality, you will want to use ==.

To compare two classes with ==, you may need to manually implement the Equatable protocol, if it is not already done.

Benefits of Each

You may choose to use value semantics when comparing with ===. You would also want to use value semantics when you want to create a shared and mutable state.

You may choose to use value semantics when you want copies of data to be independent of themselves. Value semantics are preferred when using data across multiple threads to prevent race conditions.

Do you have other thoughts on reference and value types? Reach me in the comments or on Twitter at @_alecoconnor

If you have 40 minutes, I recommend watching the Building Better Apps with Value Types in Swift WWDC video. They did a fantastic job of explaining value and reference types and had some great examples:

For another quick read, take a look at this post on the Swift Blog. When they do update it, the blog is a great resource!

Happy type-ing!

Like what you read? Give Alec O'Connor a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.