iOS retain cycle :
The typical example is A has B, B has A.
So what if A has B & C , B has C?
Is it still retain cycle?
And is there a strong relationship that the deinit
will not called by ARC
when retain cycle exists ?
Here is the example code:
class ViewModel{
func doSth(){
print("123")
}
deinit{
print("ViewModel")
}
}
class CustomView: UIView{
var viewModel: ViewModel?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
viewModel?.doSth()
}
deinit{
print("CustomView")
}
}
class ViewController: UIViewController {
var viewModel = ViewModel()
lazy var widget: CustomView = {
let v = CustomView(frame: CGRect(origin: .zero, size: CGSize(width: 150, height: 150)))
v.backgroundColor = UIColor.red
v.viewModel = viewModel
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(widget)
}
deinit{
print("ViewController")
}
}
when ViewController
popped , three deinit
method above are all called.
So there is no retain cycle.
Is it?
CodePudding user response:
An easy way to figure out if you have a retain cycle is to draw a diagram. Use arrows for strong references, and dotted arrows for weak/unowned references.
If you can follow the solid arrows from an object back to that same object, you have a retain cycle.
In your case, where A owns B and C, and B also owns C, there are 2 owning references to C, but no "backwards" strong references. There is no way you get loop back to A or B, so there is no retain cycle.
Closures are another potential source of retain cycles that isn't obvious. If you have an "escaping" closure that references "self", and you hold a strong reference to that closure, you have a retain cycle because you have an owning reference to the closure and the closure, through it's self
reference, has a strong reference to you.
Edit:
The way I teach new developers to avoid retain cycles is to think in terms of "Forward" and "backward" references. Forward references should be strong, and backward references should be weak.
If you think of a doubly linked list, the forward pointers should be strong, and the back-pointers should be weak.
If you own an object, your pointer to it should be strong. If you are that object's delegate, think of the delegate pointer as a backwards pointer. It should be weak.