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 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.
Table of Contents
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.
Related Articles
- Jan Koum, the WhatsApp Builder who went from rags to riches…for real!
- 10 Best Free PDF Readers for Windows, Mac, Android and iOS
- Top 10 Best Intercom Integrations for Customer Support
- How To Use Apple’s Developer Documentation for Fun and Profit
- 6 ways to use Microsoft Teams Slack integration for Small Businesses
- How to Integrate e-commerce Stores with eBay Sales Channel? [Top eBay Integrations]
- What is a Virtual Assistant and What they do?
- Get Started with SwiftUI for iOS
- The Hidden Symbolism of the Harry Potter Logos
- Which Are the Top 10 Applications to Integrate With Klaviyo?
Most Popular Posts
Tips and Techniques for Incorporating Coffee Pot Color in Graphic Design
By Saumya | June 8, 2023
Coral Color in Graphic Designing- Timeless or Trendy?
By Saumya | June 8, 2023
Introduction to Ebony Color in Graphic Designing: What is it and Why is it Important?
By Saumya | June 6, 2023
Help Desk Software: A Step-By-Step Guide for Effective Support Management
By Neeraj Shukla | June 6, 2023
Writesonic vs. Jasper: Workflow Automation and Integrations in AI Writing Tools
By Abhinav Girdhar | June 2, 2023