Sunday, May 09, 2010

Ouch! iPhone Memory Management

Here is my story about iPhone development update. I thought I had very good understanding of iPhone memory management. For each object created by alloc and init, a corresponding release should be made to balance its life cycle. It is simple, right? When I put my hands on my first application codes, I got hurt! But it was a good experience. Here is the story.

In my codes, one of view controller uses core data as data source. In the header file, a fetchedResultController is defined:

@interface MyViewController : UITableViewController <NSFetchedResultsControllerDelegate, UITableViewDelegate>
{
  // ...
  NSFetchedResultsController *fetchedResultsController;
  // ...
}

// ...
@property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
// ...
@end


In my .m file, the implementation of my customized getter is like this:

@synthatic fetchedResultsController;
// ...
- (NSFetchedResultsController *)fetchedResultsController {
  if (fetchedResultsController != nil) {
    return fetchedResultsController;
  }
....
  NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc]
  initWithFetchRequest:fetchRequest
  managedObjectContext:managedObjectContext
  sectionNameKeyPath:nil cacheName:@"Root"];
  aFetchedResultsController.delegate = self;
  fetchedResultsController = aFetchedResultsController;
  // [fetchedResultsController retain]; I missed this line to contain the object
  // ...
  return fetchedResultsController;}


My intension to implement getter is for this view controller class to have its own fetched result controller with the class own managed context object and fetch request. However, I did not retain the controller. The result is unexpected with the alloc and init object.

Here is a simplified example:

  instance = aInstance;
  self.instance = aInstance;



The first line is directly reference or pointer assignment. The result is that both variables are pointing to the same memory address, and both variables have the same reference count; while the second line actually calls to the setter property of instance, and the reference of right side variable is passed to the setter method. It will be up to the setter class to retain, copy or do assignment.

In my customized property getter, in order to retain my alloc and init object, there are two options. First option is to do the direct assignment and then to retain it so that object reference count is increased to 1. The second and simple option is call the setter to do it [self instance] = ... The synthetic property definition guards the "retain" feature.

I had spent almost one week of evenings and one week end time to figure the issue out. The exception I got was "EXC_BAD_ACCESS". The following is my NSLog message in the getter method with system crash messages:

2010-04-12 07:15:23.347 MyApplication[8030:207] ... 
2010-04-12 07:15:23.348 MyApplication[8030:207] MyViewController->fetchedResultsController
Program received signal: "EXC_BAD_ACCESS".

The exception happened at the end of the property getter. Now I understand the meaning of "EXC_BAD_ACCESS", at least this is one of many cases. It does say what it means: access to the memory which was released and not accessible.

Actually, I found the clue when I tried to google the issue. When I read some answers about one StackOverflow question (http://stackoverflow.com/questions/327082/exc-bad-access-signal-received). I immediately realized it was memory issue and then realized the object I tried to return was actually released.

It is a really good lesson. iPhone development is new for me, and I really en joy it when I figure out something. This is a way to gain knowledge and to make progress. After I corrected my codes, my application was back to alive and the view was displayed!

0 comments: