Retain cycle in Parent Child inheritance example

Note: ARC is enabled to demonstrate strong/weak usage of retain cycle

Parent Child example

Parent.h

Parent.m

Child.h

Child.m

main.m

So we have a Parent object that has strong reference to a child Object. Upon initialization, it creates a strong reference to the child object. When we alloc and nil out the object in main, we see the appropriate actions taken:

Result:

2015-09-10 16:28:07.667 RetainCycleEx[37844:1585148] Parent.m (init) – init
2015-09-10 16:28:07.668 RetainCycleEx[37844:1585148] Child.m (init) – init
2015-09-10 16:28:07.669 RetainCycleEx[37844:1585148] Parent.m – I’m dealloc…..my retain count is 0
2015-09-10 16:28:07.669 RetainCycleEx[37844:1585148] Child.m – I’m dealloc…..my retain count is 0

Once we allocate the Parent, it in turn allocates the Child. Once we nil out the Parent, ARC garbage collects Parent object, which calls dealloc. That dealloc will set the Child object to nil, which makes ARC call Child’s dealloc so it can clean up.

Hence, everything is as expected.

Creating the retain cycle

main.m

Say we make the Child object have a strong reference on its parent. Thus, we’ve created a circular retain cycle. When fumu gets niled, the ARC won’t garbage collect it (aka call dealloc on Parent object) because Parent is pointed to by the child. If Parent’s dealloc method do not get called, then its child object won’t get niled, and thus, the Child object will never be cleaned up. Hence this parent and its child is now floating around and ARC will never clean them up because they have a strong reference towards each other.

Result:

2015-09-10 16:36:07.856 RetainCycleEx[38356:1588472] Parent.m (init) – init
2015-09-10 16:36:07.857 RetainCycleEx[38356:1588472] Child.m (init) – init

Where the problem lies
Child.h

The problem is that our Child object’s parent pointer, is a strong reference. If you change it to weak, and run the problem again, then the dealloc gets called.

The reason is because when pointer fumu gets niled, ARC will see NO strong references on Parent, thus, it will assume its safe to garbage collect it.

Result:

2015-09-10 16:46:56.921 RetainCycleEx[39034:1592492] Parent.m (init) – init
2015-09-10 16:46:56.922 RetainCycleEx[39034:1592492] Child.m (init) – init
2015-09-10 16:46:56.922 RetainCycleEx[39034:1592492] Child.m – I’m dealloc…..my retain count is 0
2015-09-10 16:46:56.923 RetainCycleEx[39034:1592492] Parent.m – I’m dealloc…..my retain count is 0

Non Propety example

We can also use __strong and __weak to demonstrate this. Notice that we must be in an ARC environment in order to see the effects of __strong/__weak.

We first create a pointer fumu to a Parent object. Even though no __strong is specified, it is by default __strong. Then we have a weak reference to the same Parent object. we set the fumu to nil.

At this point, even though the reference fumu is niled in the auto varaibles console, you’ll see that strongFumu and weakFumu are pointing to an object with an address. That’s because we still have a strong reference to the Parent object pointing to by strongFumu.

Then we nil out strongFumu and you’ll see both weakFumu and strongFumu both being niled. That’s because the Parent object have 0 strong references on it. Thus ARC garbage collects it and Parent object’s dealloc method gets called.

//3

2015-09-10 17:04:49.289 RetainCycleEx[40294:1601178] Parent.m (init) – init
2015-09-10 17:04:49.290 RetainCycleEx[40294:1601178] Child.m (init) – init

//4

2015-09-10 17:04:49.289 RetainCycleEx[40294:1601178] Parent.m (init) – init
2015-09-10 17:04:49.290 RetainCycleEx[40294:1601178] Child.m (init) – init
2015-09-10 17:04:52.383 RetainCycleEx[40294:1601178] Parent.m – I’m dealloc…
2015-09-10 17:04:52.383 RetainCycleEx[40294:1601178] Child.m – I’m dealloc..