Computed Properties Explained In Swift

Written by Reinder de Vries on April 3 2020 in App Development

Computed Properties Explained In Swift

A computed property is a property that calculates and returns a value, rather than just store it. In this tutorial, we’ll discuss how computed properties work and how you can use them in your day-to-day iOS development.

Here’s what we’ll get into:

  • What’s a computed property?
  • How read-only computed properties work
  • Stored vs. computed properties
  • How to calculate a value with a computed property
  • Getters and setters – how they work, and why you need ’em
  • Practical examples of computed properties in iOS development

Ready? Let’s go.

  1. What’s A Computed Property?
  2. Getters & Setters for Computed Properties
  3. Read-Only Computed Properties
  4. Practical Use Cases for Computed Properties
  5. Further Reading

What’s A Computed Property?

Before we discuss computed properties, let’s do a quick recap of what properties are. Here’s a quick summary:

  • A property associates a value with a name, like a variable, and it’s a part of a class, structure or enumeration.
  • A stored property stores constant and variable values as part of a class (or struct) instance. The name in user.name = "John" is a stored property, and user is an instance of a class.
  • It’s easiest to think of stored properties as variables that are attached to instances of a class or struct. They help you organize your code better, based on the principles of OOP.

Let’s move on to computed properties. A computed property calculates a value, rather than store it. A computed property is similar to a function, in the sense that it executes some code when you call the property.

Here’s an example:

struct Rectangle
{
    var width:Double
    var height:Double

    var area:Double {
        width * height
    }
}

In the above Swift code, we’ve defined a struct called Rectangle. It has two properties width and height of type Double. The third property, called area of type Double, is a computed property. Here it is once more:

var area:Double {
    width * height
}

The above computed property will execute the code width * height, and return its value, when the area property is called. Here, check this out:

let square = Rectangle(width: 12.0, height: 12.0)
print(square.area)

In the above code, we’ve defined a square with a width and height of 12 units. We then calculate the surface area of the square by referencing the area property of square, and print out its result. Internally, the code width * height is called, i.e. 12.0 * 12.0 = 144.0, and returned.

If we had defined the area property as a function, it would have looked something like this:

func area() -> Double {
    return width * height
}

See how that works? A computed property is kinda like a function, but different. Computed properties have a dense, concise syntax – and when used well, they make for more expressive and clearer code.

Note: In the above example, for area, we’ve created a read-only computed property, which uses an implicit return. More on that, below!

Learn how to build iOS apps

Get started with iOS 13 and Swift 5

Sign up for my iOS development course, and learn how to build great iOS 13 apps with Swift 5 and Xcode 11.

Getters & Setters for Computed Properties

OK, so far we’ve established that a computed property calculates a value. Computed properties execute some code when you call ’em, and they’re different from stored properties and functions. So far so good!

Computed properties can also provide a custom getter and setter.

  • A getter is executed when the computed property is read/retrieved
  • A setter is executed when the computed property is set/changed

Let’s take a closer look with an example:

struct User
{
    private var firstName = ""
    private var lastName = ""

    var name:String {
        get {
            return firstName + " " + lastName
        }
        set(newValue) {
            let split = newValue.components(separatedBy: " ")
            firstName = split[0]
            lastName = split[1]
            print("firstName = \\(firstName), lastName = \\(lastName)")
        }
    }
}

var user = User()
user.name = "John Doe"
print(user.name)

In the above code, we’ve created a User struct with 2 private properties firstName and lastName of type String. The third property is computed, called name of type String.

The computed property name has a getter and setter defined. Here’s a quick overview of the syntax we use for that:

var property:type {
    get {
        code
    }
    set(value) {
        code
    }
}

As part of the computed property, we can specify what happens when a property is read (getter) or changed (setter). Within the getter, you’re supposed to return a value. Within the setter, you’re supposed to store or change some value.

In the previous code sample, here’s what happens:

  • We’ve defined a User struct that has a private implementation for the firstName and lastName properties. We can’t change those from the outside, but only through the name computed property.
  • When you read the name property, the code for get { ··· } is executed. You get the value of the firstName and lastName strings with a space in between.
  • When you change the value of name, the code for set { ··· } is executed. In the code, the provided string newValue is split into components, and assigned to firstName and lastName.

We can use the local newValue constant as the value that’s provided, so we have access to both the new and the current values. This newValue constant is implicitly available inside the setter, so you don’t have to declare it explitly. You can, however, provide your own constant name, if you want. Like this:

set {
    // Use `newValue` in here (implicit)
}
set(newString) {
    // Use `newString` in here (explicit)
}

Quick tip: For the sake of this example, we’re assuming that all person’s first and last names are separated with one space character. This isn’t true in the real world, of course – names come in all shapes and sizes. Yay!

Read-Only Computed Properties

We’ve looked at getters and setters for computed properties in the previous sections, but what about a computed property that only has a getter? Such a computed property is known as a read-only computed property – it can only be read, and not set.

Here, check this out:

struct Circle
{
    var radius:Double
    var circumference:Double {
        2 * .pi * radius
    }
}

In the above code, we’ve defined a struct Circle that has a stored property radius and a computed property circumference, both of type Double. We can use it like this:

let earth = Circle(radius: 6371)
print(earth.circumference) // Output: 40030.173592041145

That circumference property is computed and read-only – it only has a getter. In fact, the above declaration of circumference is exactly the same as this:

var circumference:Double {
    get {
        return 2 * .pi * radius
    }
}

Comparing it against the previous code sample, you see two differences:

  1. The get { ··· } part is removed. When left out, Swift assumes we’re declaring a read-only computed property.
  2. There’s no return statement. Since Swift 5.1, single-line expressions can omit an explicit return for the sake of clarity, brevity and expressiveness.

Awesome! Let’s look at a few real-world scenarios for computed properties, next.

Practical Use Cases for Computed Properties

When you think about it, computed properties are just functions without parameters. Are they? In essence, the whole of programming is just syntactic sugar and “structure” around 1’s and 0’s… Merely saying “Computed properties are just functions without () misses the whole point!

Let’s look at a few real-world use cases for computed properties.

First, the read-only computed property is ideal for expressing simple calculated values concisely. Consider the circumference of a circle, that we’ve discussed before. You can, for example, provide a person’s formatted address based on individual values. Like this:

struct Person {
    var street:String
    var streetNumber:String
    var city:String
    var postcode:String

    var address:String {
        "\(street) \(streetNumber)\n\(postcode), \(city)"
    }
}

let bob = Person(···)
print(bob.address) // Output: Infinite Lane 42 12A34B, Diamond City

More specifically, the above properties make sense from a stored database perspective. The address computed property is essentially a view into the model data of Person. You don’t have to store the complete address, just its individual components. You can them present them in any way you want.

Secondly, you can use computed property getters and setters to adjust other values than a property itself. Here, check out this example:

struct RentalCar
{
    var costPerDay:Double

    var costPerWeek:Double {
        get {
            costPerDay * 7.0
        }
        set {
            costPerDay = newValue / 7.0
        }
    }
}

var toyota = RentalCar(costPerDay: 12.0)
toyota.costPerWeek = 100.0
print(toyota.costPerDay) // Output: 14.28

In the above code, we’re creating a struct RentalCar that has a two properties:

  • A stored property costPerDay of type Double
  • A computed property costPerWeek of type Double

We could locally say that the cost per week of a rental is the cost per day times 7, and vice versa. In the above code, you see that the costPerDay is the absolute determining factor for renting a car for any length of time.

  • When costPerWeek is set, we divide it by 7 and write it to costPerDay.
  • When costPerWeek is read (“get”), we multiply it by 7 to get the cost per week.

In your development, you can now work with either day or week units, thanks to computed properties. Your code is, as far as this example goes, more concise and easier to read. The ratio between days and weeks is also an implementation detail of the RentalCar struct itself, so your interfacing code doesn’t have to worry about mediating between the two. Awesome!

Learn how to build iOS apps

Get started with iOS 13 and Swift 5

Sign up for my iOS development course, and learn how to build great iOS 13 apps with Swift 5 and Xcode 11.

Further Reading

In this tutorial, we’ve discussed how to work with computed properties in Swift. We’ve looked at read-only properties, getters and setters, and practical examples of computed properties in real-world iOS development.

Want to learn more? Check out these resources:

Reinder de Vries

Reinder de Vries

Reinder de Vries is a professional iOS developer. He teaches app developers how to build their own apps at LearnAppMaking.com. Since 2009 he has developed a few dozen apps for iOS, worked for global brands and lead development at several startups. When he’s not coding, he enjoys strong espresso and traveling.