Back to blog

Computed Properties Explained in Swift


Aasif Khan
By Aasif Khan | Last Updated on August 12th, 2022 6:43 am | 4-min read

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

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. A computed property calculates a value, rather than store it. 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 area property executes the code width * height, and return its value, when it’s 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!

Getters & Setters for Computed Properties

OK, so far we’ve established that a computed property calculates a value. They 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 property is read/retrieved
  • A setter is executed when the 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 two private properties firstName and lastName of type String. The third property is computed, called name of type String.

The computed property name has a custom 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 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 property that only has a getter? That’s 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. Aren’t 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.

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 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!

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 in real-world iOS development.


Aasif Khan

Head of SEO at Appy Pie

App Builder

Most Popular Posts