Lazy initialization

In the days of iOS development with OC, you’ll see a lot of lazy code:

// Take lazy loading of a UIImageView control
- (UIImageView *)imageView
{
    if (!_imageView) { 
        _imageView = [[UIImageView alloc]init];
    }
    return _imageView;
}
Copy the code

Lazy loading is the first time an attribute is accessed to determine whether the attribute has been initialized. If it has been initialized, it will be returned directly. If it has not been initialized, it will be initialized. This improves performance by delaying the initialization of the property, separating it from the initialization of the containing object.

Benefits of lazy loading:

  • You don’t have to create code all in a similar way- (void)viewDidLoadMethod, increase code readability;
  • It saves memory space by loading resources only when they are really needed.
  • When a memory warning is received,didReceviewMemoryWarningMethod is used to release resources, which can be loaded again if lazily loaded.

Swift can achieve similar lazy loading:

private var _imageView: UIImageView?
var imageView: UIImageView {
    get {
      if _imageView = = nil {
        _imageView = UIImageView()}return _imageView! 
    }
    set {
      _imageView = newValue
    }
}
Copy the code

This way, despite our requirements, the code was too much and too un-Swift. Lazy makes its debut.

Add the lazy keyword to the variable attribute to specify lazy loading:

lazy var imageView: UIImageView = UIImageView(a)Copy the code

Using the lazy keyword, we achieve the same behavior with less code.

Of course, if we want to set more attributes to our imageView, we can initialize them with a closure:

lazy var imageView: UIImageView = {
    let imgView = UIImageView()
    imageView.contentMode = .scaleAspectFill
    return imageView
}()
Copy the code

When you use lazy to modify a property, you must declare that the property is a variable.

We’ll stop there with the initialization of lazy. But as a performance optimization tool, the article can not stop there.

Lazy sequences

In the Swift standard library, both the SequenceType and CollectionType protocols have a calculation property called lazy, which returns a particular LazySequence or LazyCollection.

/// Augment `self` with lazy methods such as `map`, `filter`, etc.
extension Collection {
    public var lazy: LazyCollection<Self> { get}}func lazy<S : SequenceType> (s: S) -> LazySequence<S>

func lazy<S : CollectionType where S.Index : RandomAccessIndexType> (s: S)
                -> LazyRandomAccessCollection<S>

func lazy<S : CollectionType where S.Index : BidirectionalIndexType> (s: S)
                -> LazyBidirectionalCollection<S>

func lazy<S : CollectionType where S.Index : ForwardIndexType> (s: S)
                -> LazyForwardCollection<S>
Copy the code

These types can only be used in higher-order functions such as map, flatMap, and filter, and in an inert manner. This can also help performance in some cases, such as when using map directly:

func increment(x: Int) -> Int {
  print("Access:\(x)")
  return x+1
}

let array = Array(0..<10)

print("✅ results.")
let incArr = array.map(increment)
print(incArr[0], incArr[5])


let incArray = array.lazy.map(increment)
print("\n✅ result of using the lazy attribute :")
print(incArray[0], incArray[5])
Copy the code

Output results:

Results: Visit:0Access:1Access:2Access:3Access:4Access:5Access:6Access:7Access:8Access:9
1 6

uselazyResult of property: access:0Access:5
1 6
Copy the code

Here’s the code:

  • accessincArrAll output values are computed before the value of! Even though we only read [0] and [5], all the other entries are accessed
  • accessincArrayBecause of lazy, only two items [0] and [5] are accessed, and the items that are not cared about are not accessed.

Using lazy reduces the computation significantly. If the array size is larger and increment is more complex, the savings are even more significant.

Lazy computing is a feature of functional programming languages that you are interested in learning more about.

Lazy View

The difference from HStack/VStack without “Lazy” is loading on demand, for example, if you try to display 10,000 text on HStack or VStack, the memory immediately jumps, but LazyHStack or LazyVStack only loads the memory with text on the screen.

Of course, SwiftUI 2 also has a lazy-loading View: LazyHGrid/LazyVGrid

Note:

Additionally, be aware that the lazy keyword doesn’t perform any thread synchronization. If multiple threads access a lazy property at the same time before the value has been computed, it’s possible the computation could be performed more than once, along with any side effects the computation may have.

The lazy variable is initialized on the first access. If multiple threads access the lazy variable, the result will be unpredictable:

  • It is possible for different threads to generate different lazy variables.
  • It is possible that another thread returns this variable before the initialization is complete.