tonytran
tonytran

Reputation: 1078

do we need weak or unowned reference when doing a lazy variable, memory management

I'm experimenting with memory management in Swift by following.

class Person {
    let name: String
    //var block: (() -> Void)?

    init(name: String) {
        self.name = name
    }

    //  Declare variable clone, using self inside.
    private lazy var clone: String  = {
        return self.name   
    }()

    deinit {
        print("Destroying \(name)")
    }
    func doSomething() {
        print("Doing something for \(name)")
    }
}

var p2: Person? = Person(name: "p2")
print(p2!.clone)
p2 = nil

As you see, I'm using self inside when declaring a lazy var and I think it is still ok because when p2 is getting nil, I can see the deinit method get called.

However, if I make a change like following

    // This is a closure
    private lazy var clone: () -> String  = {
        return self.name    // leaking memory is here
    }

Now, I am getting a leaking memory.

My question is for a variable using lazy instantiation, why I don't get a leaking memory even though I am using self.I thought I had to use it otherwise I would get a leaking memory.

Upvotes: 3

Views: 2625

Answers (2)

Mtoklitz113
Mtoklitz113

Reputation: 3878

Here :

 private lazy var clone: () -> String  = {
        return self.name    // leaking memory is here
    }

You are assigning the closure itself to the variable, instead of assigning the String that it is supposed to return. And since you're using self which the closure retains, the two will never be released which can lead to a memory leak. A reference cycle is created as the closure is retained as a property and the closure retains self. Here is where the capture lists come into picture. You can fix the leak like so:

private lazy var clone: () -> String  = { [unowned self] in

        return self.name    // leaking memory is fixed
    }

Self is declared as unowned in the capture lists as it is safe to assume that it will NOT be nil at any point. If you are sure the variable will NEVER be nil, use unowned but if you think at some point it might become nil, use weak instead.

Upvotes: 7

dopcn
dopcn

Reputation: 4218

The reason you leak memory is because closure will capture self strongly in default and at the same time self hold the closure as a property strongly. It has nothing to do with lazy variable.

Upvotes: 1

Related Questions