0

I've run into a leak when trying to load saved custom objects from NSUserDefaults. Here is the code that's the culprit. Does anyone see anything that's clearly wrong?

@interface CustomQuery : NSObject <NSCoding> {
 NSString *theTitle;
 NSString *query;
}

@property(nonatomic, retain) NSString *theTitle;
@property(nonatomic, retain) NSString *query;

- (id)initWithCoder:(NSCoder *)aDecoder {

if (self = [super init]) {
    //tempTitle is leaking
    NSString *tempTitle = [[aDecoder decodeObjectForKey:@"QueryTitle"] retain];
    self.theTitle = tempTitle;
    [tempTitle release];

    //tempQuery is leaking
    NSString *tempQuery = [[aDecoder decodeObjectForKey:@"QueryValue"] retain];
    self.query = tempQuery;
    [tempQuery release];
}
return self;
}

- (void)dealloc {
 [theTitle release];
 [query release];
 [super dealloc];
}

This is also listing as a leak in Instruments

NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *dataRepresentingSavedArray = [currentDefaults objectForKey:@"savedQueries"];
if (dataRepresentingSavedArray != nil)
{

    //This is Leaking in Instruments
    NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedArray];
    if (oldSavedArray != nil) {

        //tempCustomQueryArray is also leaking
        NSMutableArray *tempCustomQueryArray = [[NSMutableArray alloc] initWithArray:oldSavedArray];
        if (savedQueries != nil) {
            savedQueries = nil;
        }
        self.savedQueries = tempCustomQueryArray;
        [tempCustomQueryArray release];
    }
 }
aahrens
  • 5,522
  • 7
  • 39
  • 63

2 Answers2

2

In this:

NSString *tempTitle = [[aDecoder decodeObjectForKey:@"QueryTitle"] retain];
self.theTitle = tempTitle;
[tempTitle release];

The retain and release aren't necessary because your property will retain the object. However, I think these two strings are a red herring; it is likely that the leak is somewhere else.

I suspect that savedQueries isn't being released in the dealloc that I would assume is not shown. That'd hang onto the queries and a bunch of other stuff.

That doesn't entirely explain where the leak of oldSavedArray is coming from (unless I'm missing something).

Turn on retain/release tracking in the allocations instrument and see where every retain/release is being called. You'll find an unbalanced one somewhere.

I wrote a blog post that is related and may be helpful.

bbum
  • 162,346
  • 23
  • 271
  • 359
  • Thanks for the help, I'll turn on those features and see if I can find more meaningful information. – aahrens Dec 06 '10 at 03:11
  • After looking into it more I had missed an obvious error. The above code that was initializing the oldSavedArray was both in my viewDidLoad method and viewWillAppear method. Thanks for your assistance – aahrens Dec 07 '10 at 15:59
0

I'm not seeing where you've implemented the encodeWithCoder delegate method, or how you're archiving (saving to NSUserDefaults). I would also try changing your CustomQuery.m methods to reflect:

- (void)encodeWithCoder:(NSCoder *)encoder
{
    [encoder encodeObject:self.theTitle forKey:@"QueryTitle"];
    [encoder encodeObject:self.query forKey:@"QueryValue"];
}

- (id)initWithCoder:(NSCoder *)aDecoder {

    self = [super init];
    self.theTitle = [aDecoder decodeObjectForKey:@"QueryTitle"];
    self.query = [aDecoder decodeObjectForKey:@"QueryValue"];

    return self;
}
Richard
  • 1,677
  • 3
  • 13
  • 15
  • I call [[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:savedQueries] forKey:@"savedQueries"]; to save my custom objects – aahrens Dec 06 '10 at 03:21