views:

1082

answers:

4

I am simply loading a plist into a temporary dictionary for initializing my data model. Unfortunately this single line of code below results in consistent leak throughout the app life cycle as per Instruments. The leaked objects being NSCFString and GeneralBlock on a Malloc and the responsible library being Foundations.

My two questions for the experienced eyes:

  1. Am I doing something strange to trigger this ? I tried surrounding it in autorelease block but it had no effect.
  2. Is there a way to print list of object references of a suspect object to get insight into the object orphaning process.

Leaking Line:

NSDictionary *tempDict = [NSDictionary dictionaryWithContentsOfFile:
                             [[NSBundle mainBundle]
                                 pathForResource:resourceName
                                 ofType:@"plist"]];

totalChapters = [[tempDict objectForKey:@"NumberOfChapters"] intValue]; 
chapterList  = [[NSMutableArray alloc] initWithCapacity: totalChapters];
[chapterList addObjectsFromArray:[tempDict objectForKey:@"Chapters"]];
+1  A: 

It appears you may be leaking at this line:

[[NSMutableArray alloc] initWithCapacity: totalChapters];

If that object isn't being released, then any objects you add to it won't be released either


Edit (because it's too long for a comment):

Instruments tells you where the memory was allocated, but not why it is still being retained. When NSDictionary loads the contents of a file, it has to create an object for each element it loads. If one later retrieves an object using objectForKey:, retain it and forget to release, a leak will be reported. The dictionaryWithContentsOfFile statement will be blamed for it because it performed the allocation.

I concur with Don's phantom debugging. Most likely you haven't released the old chapterList when you assign to it the second time.

rpetrich
The problem is in the first line:NSDictionary *tempDict ... which I am using as a temporary space to load multiple plists during the app life cycle. I expect tempDict to get released as part of the pool since I am not explicitly allocating it.The object you pointed are ivars which get released.
If chapterList has previously been assigned a value, you need to [chapterList release] before you assign a new object to it.
Don McCaughey
My response is too long for a comment, so I've edited :)
rpetrich
A: 

I am releasing all the allocated stuff in the dealloc method of this class. The TROUBLED line below gets repeatedly called in each alloc init to help me load new chapters based on user selection.

NSDictionary *tempDict = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:resourceName ofType:@"plist"]];

Since I am using convenience method on NSDictionary I don't have anything to Dealloc. But Instrument points to this particular line as the source of leak via a Malloc.

tempDict is a just a scratch space for a dictionary to load a plist and init the ivars.

A: 

Maybe you just need to set tempDict = nil once you do not need it.

Hao Zhe XU
A: 

The autorelease block only effects objects placed into the autorelease pool. So tempDict is place in the autorelease pool but totalChapters is not. If you would like to use the autorelease pool then you either want:

[[[NSMutableArray alloc] initWithCapacity: totalChapters] autorelease];

or don't use the autorelease pool and use:

[[NSMutableArray alloc] initWithCapacity: totalChapters]
and then
[totalChapters release]

Avoiding the autorelease pool is recommended unless necessary.

Hua-Ying