Search code examples
iosswiftlazy-loadingvarlet

Swift's Lazy Var


After reading about lazy variables of Swift, I have the following question:

class MainViewController: UIViewController {

      lazy var heavyClass = HeavyClass()

      func buttonPressed () {
         //Use heavyClass here
         self.heavyClass.doStuff()
      }    
}

So you use a lazy var above to optimize the code so heavyClass does not get allocated right away. So upon launching, this would be optimum since heavyClass does not get allocated upon launching time.

However, wouldn't this be the same as above?

class MainViewController: UIViewController {

      var heavyClass : HeavyClass?

      func buttonPressed () {
         //Use heavyClass here
         self.heavyClass =  HeavyClass()
         self.heavyClass!.doStuff()
      }    
}

Solution

  • In your examples the outcomes are not quite the same, in the following ways:

    1. Single instantiation. Each time buttonPressed() is called, a new HeavyClass will be instantiated. This is not the case when using the lazy keyword, which will only create the instance on first access. To match the lazy semantics you would have to check and set if heavyClass == nil before each access.

    2. Nullability. You must unwrap your heavyClass each time you want to use it, either through optional chaining (heavyClass?.doStuff()) or force unwrapping (heavyClass!.doStuff()). You are also able to set the variable back to nil, which would be a compiler error in the first example.

    The real wins of lazy variables are when you have multiple places which use the variable. I'm sure you can spot the repetition here:

    func buttonPressed() {
        if self.heavyClass == nil {
            self.heavyClass = HeavyClass()
        }
        self.heavyClass?.doStuff()
    }
    
    func aDifferentButtonPressed() {
        if self.heavyClass == nil {
            self.heavyClass = HeavyClass()
        }
        self.heavyClass?.doSomethingElse()
    }
    

    This is tidied up using a lazy variable:

    func buttonPressed() {
        self.heavyClass.doStuff()
    }
    
    func aDifferentButtonPressed() {
        self.heavyClass.doSomethingElse()
    }