[iOS] Pungent stuff: Retain cycle

December 20, 2015

Retain cycle is a serious problem. This is usually ignored by newbie or maybe happens with exp-developers, sometime we might even care about its existence. Then one beautiful day, your app is crashed due to memory leaks, you start realizing you could have retain cycles some places in your codes. Today, I’m gonna have a post to discuss more about this. As we both know, ARC – a big revolution from Apple to let developers not care about memory management, but instead, focus more about Developing and Features. It is really helpful with this, at least there will be a warning when retain cycle exits. That’s really a good point.

What is Retain Cycle?

To easy to understand, let’s jump into example right away. Firstly, we create a class called Teacher, and Student. In Teacher.h we creat a strong property of Student:

#import <Foundation/Foundation.h>

@interface Teacher : NSObject
@property (nonatomic, strong) Student *student;
@end

Next step, in Student.h make a strong property of Teacher.

#import <Foundation/Foundation.h>

@interface Student : NSObject
@property (nonatomic, strong) Teacher *teacher;
@end

Finally, in main.h:

int main(int argc, const char * argv[]) {
	@autoreleasepool {

		Teacher *aTeacher = [[Teacher alloc] init];
		Student *aStudent = [[Student alloc] init];

		aTeacher.student = aStudent;
		aStudent.teacher = aTeacher; /* this will make retain cycle */

	}
	return 0;
}

if you run the project in ARC (Cmd+R), everything seems too good but actually, a big problem is hidden. With the final line you added aStudent.teacher = aTeacher, you have made Retain cycle, and when press Shift+Cmd+B to check, memory leak warning will be coming up.

image

But Why?

In the first line, we already have an owning relationship from aTeacher to aStudent, and the line after, we have created another owning relationship from aStudent back to aTeacher. This means both objects will always be owned by another one, so the memory management will not destroy them even they’re no longer needed.

That’s Retain cycle (aka Strong reference cycle). And its consequence is making memory leaks.

image

Solution

To avoid that, remember to let make a weak relationship to parent, that is Teacher in this case. It means aStudent will be destroyed when it is no longer exits, therefor, aTeacher will be the same.

#import <Foundation/Foundation.h>

@interface Student : NSObject
@property (nonatomic, weak) Teacher *teacher;
@end
image

Addtions

The very important case for this is using delegate (for UITableView, UIScrollView, …), you must not forget to let delegate property as weak.

@property (nonatomic, weak) id <MyCustomDelegate> delegate;

Summary

This is retain cycle in normal case, there is a case, that called Retain cycle in blocks, I will introduce for you guys in next post. Please be paintent.

You could find more details in this post.