“This is the 19th day of my participation in the First Challenge 2022. For details: First Challenge 2022”

Deferred storage property

Support will be stored in the Swift attribute is set to delay storage properties, the so-called delayed storage properties, refers to the class instance structure, storage properties do not delay construction or initialization, only when developers call class instance of this attribute, this property to complete construction or initialization, this system will greatly reduce the time to the structure of the class instance:

  • The initial value of a deferred storage attribute is not evaluated until it is first used.
  • With keywordslazyTo identify a deferred storage property;

Note on deferred storage properties

We need to pay attention to two things when creating the deferred storage property:

  • The deferred storage property must have an initial value:

  • The deferred storage property must be usedvar, cannot be usedletKey words:

A deferred storage property is defined as follows:

class Person {
    lazy var age: Int = 18
}
Copy the code

Delay computation-time validation of storage properties

We said at the beginning of this article that the initial value of a deferred storage property is not evaluated until it is first used, so how do we verify that? Let’s look at the following example code:

We can format the memory address of p to see its memory status. The first two are metadata and refCount, so the third is the value of age, which has not been called yet, and its value is 0. Let’s do the next step:

By printing the result, we find that the value of p.age is stored in memory only after it is called.

Analysis of delayed storage properties

We generate SIL files to analyze the deferred storage property AGE:

Generate the SIL file as follows:

As you can see from its definition in the SIL file, the deferred storage property is an optional type and is final;

So how does the deferred storage property implement the above logic that the first access has no value and the second access has a value (that is, the first use before calculating)? We find the implementation of its access mechanism in the SIL file:

With its initialization implementation we can see that it is given a default enumeration value optional. none, like nil in OC, which is null in Swift; That’s why we didn’t set it the first time we accessed it, but how did we do it the second time?

We find the getter method for age in the SIL file:

Through enumeration matching analysis in its implementation, bb1 code block is executed if age has a value, bb2 code block is executed if age has no value; When we first looked at it, it had no value, so let’s analyze the bb2 code block first:

In the BB2 code block, values are mainly constructed and assigned to enumeration variables; When we access it for the second time we will have the value and jump to the bb1 code block:

Return the value directly in the BB1 code block;

The mechanism of lazy storage properties being evaluated only after use is essentially the same as lazy loading, which can save memory space.

Thread safety of deferred storage properties

Lazy storage does not ensure that the property is accessed only once. If there are multiple threads accessing the property, each thread may call the property, so the assignment operation may be executed multiple times. Therefore, the lazy storage property is not thread-safe.