This is the 12th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021


The introduction

You probably use the Lazy keyword in your daily development. So what are the benefits of using it? When do you need it? Let’s take a look

There are many things you can do with Lazy:

  • Instantiate an object without initializing some or all of its members
  • It is never executed before being called
  • Store calculated values and prevent double calculations

The statement Lazy

Member variables can be declared as Lazy simply by adding a Lazy keyword in front of them. The lazy member must be declared as var. What Apple said:

You must always declare a lazy property as a variable (with the var keyword), because its initial value might not be retrieved until after instance initialization completes. Lazy attributes must always be declared mutable (using the var keyword) because they may not be able to retrieve their initial value until the instance initialization is complete

Since all constants must have a value at the end of initialization, it is necessary to declare the lazy attribute as var. For example, 🌰. The fullname in the code is a constant and is initialized without an assignment, so an error is reported. The other, heavyComputation, is declared lazy and initialized with no assignment, so no errors are reported. I think you all understand that.

By declaring the property lazy, you ease the initialization effort. This is lazy loading.

Lazy loading

Another benefit of using lazy: faster initialization. As developers, we all want to instantiate our objects as soon as possible. Therefore, any heavy tasks or calculations that are avoided during initialization must also be avoided. Don’t call them until you really need them. Let’s look at an example.

As is evident from the above example, all of the computation is done when the User instance is initialized. This is because the heavycalculation is declared as a let constant and needs to have a specific value at the end of initialization. Therefore, it is calculated at the same time. That’s not what we want.

We declare the heavycalculation as lazy, and its value is not evaluated when initialized until the first call:


Avoid double counting

We can also compute attributes to achieve lazy loading: Note the difference between the following code and the above code:

It is clear from this example that the calculated properties are also not evaluated at initialization.

But does that mean that the calculated property is similar to the lazy property? Although they look similar, they have a very basic difference that makes lazy even more useful.

Let’s try accessing the calculated properties multiple times and see what happens.

As you can see from the code, when we access the calculation property * heavycalculation multiple times, we compute it once per visit (in this case, twice).

Let’s see what happens when the heavycalculation is declared lazy and called several more times:

The property is evaluated only once this time. This means that after a value is evaluated the first time, its value is saved for future use, and unlike with evaluated attributes, the value is not evaluated twice after being declared lazy.

Therefore, based on the example above, we can easily determine that lazy attributes store values and will not be evaluated each time they are accessed. As a result, significant processor resources and time are saved.


Precautions for Use

Now that we understand how laziness works, we must understand how it is used and be careful when we use it.

Note that because the lazy attribute is evaluated only once, the internal logic cannot depend on other variables, especially those that change frequently. This is because, after the first calculation, the lazy property’s value cannot be updated synchronously when the value of the other variables changes, causing errors when used.

In addition, lazy is not thread-safe. This means that when we access the same variable on different threads, we may get different values. What Apple said:

If a property marked with the lazy modifier is accessed by multiple threads simultaneously and the property has not yet Been initialized, there’s no guarantee that the property will be initialized only once. If a property marked as lazy is accessed simultaneously by multiple threads and the property has not been initialized, there is no guarantee that the property will be initialized only once.

This suggests that using too much lazy can actually produce unexpected errors. But at some point, we might want to do something lazy. Since the UI is always refreshed on the main thread, this makes it a good option for lazy loading.

conclusion

Lazy is familiar, but it should not be used just for the sake of use. Also watch out for multithreading pitfalls.