I have been pulling my hair out lately with iPhone development memory management techniques in Objective-C, and I thought I'd share one of my recent understandings.
#import "CustomHeaderViewController.h"
@interface CustomTableView : UITableViewController {
CustomHeaderViewController *tableHeader;
}
@property (nonatomic, retain) CustomHeaderViewController *tableHeader;
@implementation CustomTableView
@synthesize tableHeader;
- (void)viewDidLoad {
[super viewDidLoad];
// initialize my table header here.
}
- (void)dealloc {
[tableHeader release];
tableHeader = nil;
[super dealloc];
}
Here's where my mistake began. I know that the UITableView has a setTableHeaderView method, so I used it, directly allocating my new CustomHeaderViewController as I did it.
- (void)viewDidLoad {
[super viewDidLoad];
self.tableHeader = [[CompanyTableViewHeader alloc] init];
[self.tableView setTableHeaderView: tableHeader.view];
}
My project builds correctly, and everything seems to work fine, but there's a memory leak. To see this, let's look at the retain counts in my code now:
- (void)viewDidLoad {
[super viewDidLoad];
// [tableHeader retainCount] == 0
self.tableHeader = [[CustomHeaderViewController alloc] init];
// [tableHeader retainCount] == 2
[self.tableView setTableHeaderView: tableHeader.view];
// [tableHeader retainCount] == 2
}
- (void)dealloc {
// [tableHeader retainCount] == 2
[tableHeader release];
// [tableHeader retainCount] == 1
tableHeader = nil;
[super dealloc];
}
So when my UITableViewController is deallocated, the CustomHeaderViewController instance still has a retain count of 1. The problem lied in the line where I first allocated the instance (creating a retainCount of 1), and immediately assigned it to the to the tableHeader pointer (bumping the retainCount to 2). I can do two things to remedy this. First, I could change my tableHeader setter to only assign instead of retain:
@property (nonatomic, assign) CustomHeaderViewController *tableHeader;
The preferred way, however, would be to allocate the CustomHeaderViewController to a temporary pointer, then release it when done.
- (void)viewDidLoad {
[super viewDidLoad];
CustomHeaderViewController *header = [[CustomHeaderViewController alloc] init];
self.tableHeader = header;
[header release];
[self.tableView setTableHeaderView: tableHeader.view];
}
There you go. I hope this post saves someone the hour of debugging I've already lost!
P.S.: I apologize for the styles of the code snippets, I have never posted code on this blog before. If you have recommendations on how to improve formatting when copy-pasting from Xcode to the Blogger WYSIWYG editor, let me know!



