Why lazy property and didSet will end up with recursion call?

Viewed 214

The below code works just fine

class A {

    var s: MyStruct! {
        didSet {
            print("didSet")
            print(n)
        }
    }

    lazy var n: Int = s.x + 1

    func viewDidLoad() {
        s = MyStruct()
    }
}

struct MyStruct {
    var x = 1
    init() { print("MyStruct init") }
}

let a = A()
a.viewDidLoad()

with output :

MyStruct init
didSet
2

However, if we have lazy properties as follow

class A {

    var s: MyStruct! {
        didSet {
            print("didSet")
            print(n)
        }
    }

    lazy var n: Int = s.x + 1

    func viewDidLoad() {
        s = MyStruct()
    }
}

struct MyStruct {
    lazy var x = 1
    init() { print("MyStruct init") }
}

let a = A()
a.viewDidLoad()

It will end up with endless recursion call

MyStruct init
didSet
didSet
didSet
...

Why lazy property and didSet will end up with recursion call?

1 Answers

You are declaring a lazy stored property. When the struct is initialized with MyStruct(), there's no value stored in MyStruct.x.

It will only be populated when it is accessed first time. When a property is changed, a value type like struct MyStruct is considered to be changed as well - so it's didSet is invoked (again) upon first access of x.

Here's how it becomes infinite loop.

  1. viewDidLoad() > A.s.setter > A.s.didset [Expected]
  2. First access of A.n.getter for the print(n) part.
  3. s.x is lazy stored and upon first value population (update), it triggers - A.s.modify > A.s.didset & we land again at A.n.getter.
  4. It loops indefinitely between 2 & 3 after this.

See screenshot - enter image description here

Related