Home > Back-end >  Closure - Timing of deinit self object
Closure - Timing of deinit self object

Time:09-19

class Increment {
   var number = 0
 
   init(){
       print(#function)
    }
   deinit {
       print(#function)
   }
   //    let incrementNumber would give an error — 1
   lazy var incrementNumber: (Int) -> () = { [weak self] value in
       self?.number  = value
       print(self?.number)
   }
}
 
do {
   let increment = Increment().incrementNumber(3)
}
// output
init()
deinit
nil

if I separate the line, self is still alive when the closure is executed.

let increment = Increment()
increment.incrementNumber(3)
// output
init()
Optional(3)
deinit

Can anyone please explain why the Increment get deinit before the incrementNumber() call?

CodePudding user response:

First of all you need to know definition of lazy variable.

According to apple docs, A lazy stored property is a property whose initial value isn’t calculated until the first time it’s used. You indicate a lazy stored property by writing the lazy modifier before its declaration.

Means that when the class is initial, they don't know they have variable lazy inside which is incrementNumber.

That the reason when you call

do {
   let increment = Increment().incrementNumber(3)
}

Increment don't recognized incrementNumber in the class when you access directly. So Swift only see that you do nothing with Increment class in the rest of code then it automatically deinit the unused class.

Update: As Mr. DuncanC's mentioned, because of deinit class first so the compiler create an instance of Increment as AutoReleased, and keep it in memory in order to evaluate the second part of the expression

At the second, you call

let increment = Increment()
increment.incrementNumber(3)

Means that you make a class at first then you make lazy variable ( Swift sees that you do something with that class in second line so it waits until everything in class is called). Then in the rest of code class Increment is unused then it automatically deinit. That's the reason you see lazy is call before deinit.

For more further knowledge, you can do like making a not lazy function to see the difference.

class Increment {
   var number = 0

   init(){
       print(#function)
    }

   deinit {
       print(#function)
   }

    public func increaseNumber(_ value: Int) {
        self.number  = value
        print(#function)
    }
}

do {
    let increment = Increment().increaseNumber(3)
}

//init()
//increaseNumber(_:)
//deinit

As you can see that increaseNumber is called before deinit because the class know that it owns func increaseNumber so it was called. Then in the rest of code class Increment is unused then it automatically deinit.

  • Related