Home > Articles > Programming > General Programming/Other Languages

  • Print
  • + Share This
This chapter is from the book

Reference and Value Types

Structures and classes are far more alike in Swift than they are in most languages. However, there is one major difference in how they operate: classes are reference types; structures, enums, and tuples are value types.

What does it mean to be a value type? For one thing, a value type is always treated as a single value, even if it is composed of several individual values via its properties.

In practical terms, this means that when a value type is assigned or passed as a parameter, a copy is made. The following code demonstrates the effect with the Vector structure:

var vector0 = Vector(x: 0, y: 0)        vector0 = {x 0, y 0}
var vector1 = vector0                   vector0 = {x 0, y 0}, vector1 = {x 0, y 0}
vector0.x = 1                           vector0 = {x 1, y 0}, vector1 = {x 0, y 0}

When vector0 is assigned to vector1, the entire value of vector0 is copied into the memory represented by vector1. When vector0 is changed, vector1 is unaffected.

Contrast this behavior with classes, which, again, are reference types:

let ball0 = Particle()        ball0        -> Particle: {x 0, y 0} ...
let ball1 = ball0             ball0, ball1 -> Particle: {x 0, y 0} ...
ball0.particle.x = 1          ball0, ball1 -> Particle: {x 1, y 0} ...

Even though you assign ball0 to ball1, there is still only one Particle instance in existence; no copies are made. The ball0 constant is a reference to the instance, and when ball0 is assigned to ball1, ball1 is then a reference to the same instance.

(A reference is similar to a pointer in C-based languages. However, a pointer stores the actual memory address of the object and you can access that address directly. A Swift reference does not provide direct access to the address of the object being referenced.)

There is another reference type. Functions are types so that a function can be passed in to other functions as a defined parameter, or even assigned to a property. This is the basis of closures, which you saw briefly earlier in this chapter, and which you will see again in Chapter 15.

Implications of reference and value types

Passing by reference instead of by value has two main implications. The first has to do with mutability. With a value type the code manipulating that value has complete control over it.

Reference types, however, are much different: any part of the software that has a reference to an instance of a reference type can change it. In object oriented programming this can be desirable, but in complex (and especially multithreaded) software it is a liability. An object being changed “behind your back” can cause crashes at best and strange or difficult-to-debug behavior at worst.

Swift constants help further illustrate this point. A constant value type cannot be changed once it is defined, period:

let vector: Vector if someCondition {
    vector = Vector(x: 0, y:  1)
else {
    vector = Vector(x: 0, y: -1)
vector.x = 1       // Error: Immutable value 'vector' may only be initialized once

A constant reference provides no such protection. Only the reference itself is constant.

let cannonball = Particle()
cannonball.velocity = Vector(x: 100, y: 5)     // No error!

Note that constants within a class or structure are constant. The Rocket class’s thrust property, defined with let and given an initial value in the initializer, cannot be changed:

let rocket = Rocket(thrust: 10.0, thrustTime: 60.0)
rocket.thrust = 3                 // Error: Cannot assign 'thrust' in 'rocket'

Choosing between reference and value types

How does a Cocoa programmer decide whether to use a structure or a class for their new type? In order to answer that you will need to know how the type will be used.

The vast majority of Cocoa is built on reference types: subclasses of the Objective-C base class NSObject, which provides a lot of important functionality for Cocoa. As such, large portions of your app, namely the controller and view layers, will also need to descend from NSObject.

The model layer is where the answer gets fuzzy. Model-oriented Cocoa technologies such as KVC, KVO, and Bindings also depend on NSObject, so many app’s models will also. For other apps whose models are perhaps more heavy on logic and computation, and less about binding to the UI, you are free to choose the Swift type that makes the most sense for the problem you are trying to solve. Do you want the shared mutable state provided by reference types, or do you prefer the safety of value types? Both have their advantages and costs.

Cocoa, with its deep roots in MVC and Objective-C, will always rely heavily on reference types. In comparison to Objective-C, however, Swift takes great strides in making value types powerful. As a Cocoa programmer, both will be important tools in your belt.

  • + Share This
  • 🔖 Save To Your Account