Retain cycle between class and struct
TL;DR There's a retain cycle, but you can see it for yourself!
struct X {
let propertyOfTypeY: Y
}
class Y {
var propertyOfTypeX: X?
deinit {
print("I was deinit'ed")
}
}
do {
let y = Y()
let x = X(propertyOfTypeY: y)
y.propertyOfTypeX = x
}
// y and x should be dealloc'ed here, because the "do scope" ends
Comment out y.propertyOfTypeX = x
and I was deinit'ed
will be printed, But if you do that assignment, deinit
is never called.
Same thing can happen if you use a closure.
Memory graph shows reference cycle
There is definitely a retain cycle.
Solution: It should unowned
or weak
to break the cycle
struct X {
unowned let propertyOfTypeY: Y
}
class Y {
var propertyOfTypeX: X?
deinit {
print("Y deallocated")
}
}
do {
let y = Y()
let x = X(propertyOfTypeY: y)
y.propertyOfTypeX = x
}
Yes, you have a retain cycle.
y.propertyOfTypeX = x
copies the value x
to y.propertyOfTypeX
, including the
property x.propertyOfTypeY
which is a reference to y
.
Therefore
y.propertyOfTypeX?.propertyOfTypeY === y
holds. What you have is essentially the same as
class Y {
var propertyOfTypeY: Y?
}
var y = Y()
y.propertyOfTypeY = y
only that propertyOfTypeY
is part of a struct X
(and that x
holds an additional reference to y
).