Lazy Closures Using Swift

Delay that heavyweight work

Steven Curtis
3 min readDec 18, 2022

--

Photo by Adrian Swancar on Unsplash

I’ve previously written an article about Lazy Variables but feel that it doesn’t go into enough detail about closures to set up a property and I’m not that happy about the examples used.

Time has passed. I’m now a better coder. Can I write a better article?

Let’s get into it.

Terminology

Closure: A self-contained block of functionality that can be passed around

lazy: A keyword indicating that it is a property whose initial value isn’t calculated until the first time it’s used. Must be declared as a variable (with the var keyword)

Using A Closure To Initialize A Property

Why

When you want to set up a property but the initial value is relatively expensive to create, you might want to ensure you do it *just once* and *only when necessary*.

We can do that by **using a closure*.

The Example

If we create some code to read a json file and output a String if the file is successfully read. This isn’t necessary production-ready code for reading a file (hey, it works) but is a good example for this particular article.

final class FileReader {
func readFile() -> String? {
do {
guard let fileUrl = Bundle.main.url(
forResource: "fav",
withExtension: "json"
) else {
fatalError()
}
let text = try String(contentsOf: fileUrl, encoding: String.Encoding.utf8)
return text
} catch {
return nil
}
}
}

let reader = FileReader()
print(reader.readFile()) // Optional("{ \"favourites\": [] }\n")

If we call readFile repeatedly the system has to go away and read the file multiple times. Since we know that fav.json isn’t going to change (it’s a static file here) in between execution that is rather wasteful indeed!

Using a closure

Here we are using a closure to make sure that we are only reading that file a single time. the lazy keyword means that the closure is only created once and ()

--

--