Lazy Computed Properties in Swift


Aasif Khan
By Aasif Khan | Last Updated on December 22nd, 2021 6:42 am | 4-min read

Lazy computed properties make your iOS development more efficient and easier to read. It’s a bit of syntactic sugar around the lazy keyword and computed properties, as you’ll find out in this tutorial.

Here’s what you’ll learn:

  • What computed properties are, and when you should use them
  • What lazy loading is good (or bad) for…
  • How and why to use lazy computed properties

We all know lazy programmers are the best programmers, so you’ll want to pay close attention in this blog post. What’s that Bill Gates quote again?

I choose a lazy person to do a hard job. Because a lazy person will find an easy way to do it.

What Are Computed Properties?

You know what a stored property is, right? It’s a variable that’s part of a class object. You use it to store stuff. You also use properties to structure your code better.

Here’s a class that defines 3 properties:

class Person {
var legs = 0
var eyes = 0
var arms = 0
}

Here’s how you use it:

var person = Person()
person.legs = 3
person.eyes = 2
person.arms = 2

See how we changed the property legs to 3?

OK, now let’s get into computed properties. Just like functions, computed properties calculate a value and then return it.

Like this:

class Circle {
var radius:Double = 0

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

That’s a class called Circle with two properties. The first one radius, with type Double, is pretty ordinary. The second property, circumference of type Double, is a computed property.

Instead of storing a value it returns a value by executing a bit of code. In the example above, the circle circumference is calculated as C = 2 π r.

You can now use the above Circle class like this:

var cookie = Circle()
cookie.radius = 42.0
print(cookie.circumference)

See how you can just type cookie.circumference and get the calculated result of the property?

Computed properties have one downside: every time you access them, they’re re-calculated. This can be a disadvantage if the value of the property doesn’t change or its calculation is resource intensive. You’d recalculate the value when you don’t have to! That’s a waste of computer resources.

Is there a way to solve that?

How To Use Lazy Loading

OK, let’s talk about initialization for a bit. Every time you create an object in Swift, it’s initialized.

You can describe “initialization” as setting a variable to an initial value. An object can have properties, so when you initialize an object, its properties are initialized too.

Let’s say I have a car with an advanced GPS navigation system. When I’m taking the car some place I know well, I don’t need navigation – I can just drive there. However, if I’d just initialize the car, the navigation system would be initialized as well – even if I don’t use it. That’s a waste of resources!

class Car {
var navigation = GPS()
}

var car = Car()
// car.navigation is now initialized too 🙁

In the above code, we’re initializing a Car object. This will also initialize a GPS object, which is assigned to the navigation property. If the initialization of a GPS object is slow or time-intensive, then the initialization of Car is also going to be slow.

How can I use my car’s resources more sensibly? With lazy loading!

With lazy loading, the initial value of a property is only calculated when it’s first used. If it’s not used, it’s not calculated.

Lazy loading is helpful in two scenarios:

  • When the value of the property is dependent on factors unknown at initialization of the object
  • When the initial value of the property requires complex computations or is intensive to calculate

In both scenarios it doesn’t make sense to initialize the property when the object is initialized, so that’s when you use lazy loading.

Using lazy loading is easy: simply prepend the property with the lazy keyword. You can only use lazy with var and not with let.

Like this:

class Car {
lazy var navigation = GPS()
}

Why don’t you try it out for yourself? Execute the code below in the Swift Sandbox. First, run the code with lazy. Then, remove the lazy and see the change in the code’s output.

class GPS {
init() {
print(“Initializing GPS…”)
}
}

class Car {
lazy var navigation = GPS()
}

var car = Car()

When you run the above code with the lazy attribute for property navigation, that Initializing GPS… isn’t printed when car is initialized on the last line. When you remove lazy, the property navigation is initialized when car is initialized, and therefore it prints Initializing GPS….

Awesome!

How does this connect back to computed properties? Well… you can’t lazy load computed properties. This, for example, doesn’t work:

class Circle {
var radius:Double = 0

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

// Output: ‘lazy’ may not be used on a computed property

See how we made circumference lazy? That won’t work…

Lazy Computed Properties

There’s a trick, however, to make lazy computed properties. Here, check this out:

class Circle {
var radius:Double = 0

lazy var circumference:Double = {
return Double.pi * 2 * self.radius
}()
}

A few things have changed:

  • The property circumference uses lazy loading with the lazy keyword
  • The circumference property now uses a closure to calculate the circumference of the circle

The closure itself is invoked when the circumference property is accessed, because of that last (). It’s essentially a closure that’s immediately called. Because it’s lazy, the closure is only executed once when the property is accessed for the first time. That’s a lazy computed property!

The trick is combining a closure and lazily invoking it. When you access the circumference property you implicitly call the closure, and get its result.

Quick Tip: Lazy computed properties are only calculated once: when they’re first accessed. Depending on your code, and code you work with, this is a Good Thing or a cause of weird bugs!

Lazy computed properties come in handy in a few scenarios:

  • When it doesn’t make sense to set an initial value when initializing the object, for instance because it depends on unknown outside factors.
  • When a computed property is computationally intensive, for instance when it calculates something complex

Lazy computed properties also have another added benefit: syntactic sugar.

Sometimes it’s just nicer and more elegant to define a property as a lazy computed property, instead of writing it as a function. After all, you can code a function in such a way that it’ll only recalculate a returned value if it hadn’t done so before – right?

Keywords like lazy, and closures, can add to the readability and maintainability of your code. With lazy computed properties you can keep your code closer together, adding a property’s logic near the property declaration itself. Neat!

Further Reading

Lazy computed properties – so now you know!

Lazy loading postpones initializing a property until it’s first accessed. Using the lazy keyword isn’t allowed for computed properties, so you use an implicitly invoked closure to get the same effect.


Aasif Khan

Head of SEO and Author at Appy Pie

App Builder

Leave a Reply

Your email address will not be published. Required fields are marked *

Most Popular Posts