Lazy Computed Properties in Swift

Written by Reinder de Vries on August 5 2020 in App Development, Swift

Lazy Computed Properties in Swift

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 article.

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.

Ain’t that the truth! Let’s get to it…

  1. What Are Computed Properties?
  2. How To Use Lazy Loading
  3. Lazy Computed Properties
  4. Further Reading

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?

Learn how to build iOS apps

Get started with iOS 14 and Swift 5

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

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!

Learn how to build iOS apps

Get started with iOS 14 and Swift 5

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

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.

Want to learn more? Check out these resources:

Reinder de Vries

Hi, I'm Reinder.
I help developers play with code.

Get the Weekly

Get iOS/Swift tutorials and insights in your inbox, every Monday.
  • This field is for validation purposes and should be left unchanged.

Most Popular

Browse Topics

Swift Sandbox

Code Swift right in your browser!
Go to the Swift Sandbox

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.

×

Build great iOS apps
Learn how in my free 7-day course

  • This field is for validation purposes and should be left unchanged.

No spam, ever. Unsubscribe anytime. Privacy Policy