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
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.