swiftclosuresretain-cycle

closure and retain cycle


I am trying to pass a closure from one class to another.
But I am getting a retain cycle. I am new to closures and retain cycles.
I spent a couple of hours reading tutorials but I didn't understand how to do it.

I have two classes A and B. B hold an instance of A.
A has a property of type closure. B set the closure to one of his methods.
When B "clicked" B call to a method in A that uses the closure.

I know that I have a retain cycle because I am not getting the deinit prints.
My output is:

b clicked
b_case
from b

instead of:

b clicked
b_case
from b
Deinitialization B
Deinitialization A

Thanks

class A {
    var b_code:(()->Void)?
    var b_case = false
    func DoSomeThing () {
        if b_case {
            print("b_case")
            b_code!()
        }
        else {
            print ("other case")
        }
    }
    init () {}
    deinit {
        print ("Deinitialization A")
    }
}

class B {
    let a = A()
    let b_value = "from b"
    
    
    init(){
        a.b_case = true
        a.b_code = someCode
    }
    deinit {
        print ("Deinitialization B")
    }
    
    func someCode () {
        print(b_value)
    }
    
    func click () {
        print ("b clicked")
        a.DoSomeThing()
    }
}

var b : B? = B()
b!.click()
b = nil

Solution

  • You're correct. B is retaining A, but A is retaining as its b_code property a function that refers to (captures) B. That's a retain cycle.

    I am trying to pass a closure from one class to another

    No you're not. In this line

     a.b_code = someCode
    

    the term someCode is not a closure. It is a method reference. That's the trouble.

    Change

    a.b_code = someCode
    

    To

    a.b_code = { [weak self] in print(self?.b_value) }
    

    Or possibly

    a.b_code = { [weak self] in self?.someCode() }
    

    The point is that you must assign to b_code an anonymous function (what you call a closure), not a method reference, because that's the only way you can have a capture list that lets you manage the memory of the captured reference to self to break the retain cycle.