views:

41

answers:

2

I am getting memory leaks pointing to the line "NSDictionary *dw = [NSDictionary dictionaryWithContentsOfFile:path];" by using following code

NSDictionary    *_allData;

@property (nonatomic, retain) NSDictionary  *allData;

@synthesize allData = _allData;

+ (NSString*)getNSPath

{
 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

 NSString *documentsDirectory = [paths objectAtIndex:0];

 NSString *path = [documentsDirectory stringByAppendingPathComponent:@"alarm.plist"];

 return path;
}


- (NSDictionary *)allData
{
 NSString *path = [saveAlarm getNSPath];
 NSDictionary *dw = [NSDictionary dictionaryWithContentsOfFile:path];


 _allData = [NSDictionary dictionaryWithDictionary:dw];

    return _allData;
}

The data are changing in the pList and when I ask to retrieve what is new there by property then it leaks. Any recommendation how to make clear? Or how to implement this kind of thing without leaks?

Thanks

+2  A: 

You need to release _allData before reassigning it. You also need to retain it when you assign it.

EDIT: Incorporating Robert's improvement to get rid of an unneeded NSDictionary.

EDIT2: Because you're returning an object across an API boundary, it need to be retuned as an autoreleased object.

- (NSDictionary *)allData
{
     NSString *path = [saveAlarm getNSPath];
     [_allData release];
     _allData = [[NSDictionary dictionaryWithContentsOfFile:path] retain];

    return [_allData autorelease];
}

The code you posted is a bit odd in that you're creating a property called allData, telling it to use _allData as the ivar (with @synthesize) and then implementing a custom getter that sets the ivar. If you declare the property as readonly, you can remove the @synthesize statement.

If you're only using _allData inside this method and not anywhere else in this class, you can get rid of it entirely. Here's a much simpler version that does the same thing:

- (NSDictionary *)allData
{
     NSString *path = [saveAlarm getNSPath];
     return [NSDictionary dictionaryWithContentsOfFile:path];
}
Robot K
This solution makes memory leak 864 bytes at the line where retain has been added. Not sure why should I retain it when it is class method.
Vanya
Ah. As you're returning an object across API boundaries, you need to return it as autoreleased. I'll update the code.
Robot K
You need to retain it because you're storing it in an ivar. Otherwise, the object will be released while your ivar still has a reference to it.
Robot K
It's also important to note that Instruments is showing where the leaked memory was allocated, not where the leak occurred. You need to look through all the retain and release calls on the object and find the extra retain or missing release.
Robot K
Taking this solution + changing property as readonly and no leaks. Thanks
Vanya
A: 

Why don't you replace

NSDictionary *dw = [NSDictionary dictionaryWithContentsOfFile:path];


_allData = [NSDictionary dictionaryWithDictionary:dw];

With

_allData = [NSDictionary dictionaryWithContentsOfFile:path];

Then you don't have to worry about the dw NSDictionary's autorelease which is probably causing your leak.

Robert Redmond
It's a good suggestion in that it's far less code and you don't create an extra dictionary, but that would still leak. The leak is because you're assigning a new NSDictionary to _allData without first releasing the existing value.
Robot K
This solution make no leaks at start, but bit leaking (32 bytes) when I ask for new values to retrieve....so no progress so far
Vanya