How is memory allocated for closures & what is its

2019-09-09 09:39发布

问题:

I want to understand in depth about closures and their mechanism of being allocated and usage. After reading and using them a while I have come up with some questions that are really eating up my head:

Question - 1 How is a closure used as a variable different from a normal variable from memory allocation point of view?

eg: let x:NSString ={}() & let x = NSString()

Question-2 How exactly the memory allocation happens for a block?

Please kindly explain these so as that any readers having similar kind of doubts might be beneficial from it.

**EDIT* The answer to this question by Shadow was to an other direction of this question which has been edited.

回答1:

For stored properties with default values or default closures memory allocates immideatly, before init method called. You can not use self or properties for defining other property by default value.

Closures from your example usually used on this step to define lazy properties; they should be var and marked with lazy keyword:

class myClass {
    let x: NSString? = nil
    let q: NSString? = {return "q"}() //allocates before class init; deallocates imidiatly
    lazy var y: NSString = {
        let z  = self.x
        return z ?? ""
    }()                               //allocates on first property call; deallocates imidiatly
}

Memory for lazy properties will be allocated on first property call. Construction {/*...*/}() means that this closure will be executed just at call moment and will return result of calculation (you can look at this like at unnamed function), not reference to this closure. This is very important moment: you are not retain closure, this closure allocates only for execution moment and deallocates just after return, so you don't need care about strong cycle reference problem.

Other thing - when you saving reference to closure:

class myClass {
    let x: NSString? = nil
    var closure: () -> NSString = {return "q"} //allocates before class init; deallocates on references release
    lazy var lazyClosure: () -> NSString = {
        let z  = self.x
        return z ?? ""
    }                                        //allocates on first property call; deallocates on references release
}

Memory for this closures allocates at same time as in previous case, but they will continue to live until have any references. You can look at closures here like at separate objects. Cycle reference problem can arise here. closure is not capture anything, so there are no problems with it, but lazyClosure capture self. If we will never call lazyClosure there will be no problems, since this closure will never allocates. But if we will call it, it will be allocated, it will capture self, and there will be strong cycle reference: self points to lazyClosure instance, lazyClosure points to self instance. To solve this problem you should make one of references weak, you should use capture list: insert [weak self] in or [unowned self] in in lazyClosure body. [unowned self] in in our case, since if property called, then self is not nil.

lazy var lazyClosure: () -> NSString = {
    [unowned self] in
    let z  = self.x
    return z ?? ""
}