views:

226

answers:

1

I found a leak in my code where archiving and unarchiving an NSURLResponse was causing a leak, and I can't figure out why.

   - (void)doStuffWithResponse:(NSURLResponse *)response {
        NSMutableData *saveData = [[NSMutableData alloc] init];
        NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:saveData];
        [archiver encodeObject:response forKey:@"response"];
        // Encode other objects
        [archiver finishDecoding];
        [archiver release];
        // Write data to disk
        // release, clean up objects
    }

    - (void)retrieveResponseFromPath:(NSString *)path {
        NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:[NSData dataWithContentsOfFile:path]];
        NSURLResponse *response = [unarchiver decodeObjectForKey:@"response"];
        // The above line leaks!!
        // decode other objects
        // clean up memory and do other operations
    }

Instruments reports a leak when I unarchive the NSURLResponse. If I comment that out and do not use it, there is no leak. What was interesting was instead I saved the pieces of the NSURLResponse there is no leak:

    // Encode:

 [archiver encodeObject:[response URL] forKey:@"URL"];
 [archiver encodeObject:[response MIMEType] forKey:@"MIMEType"];
 [archiver encodeObject:[NSNumber numberWithLongLong:[response expectedContentLength]] forKey:@"expectedContentLength"];
 [archiver encodeObject:[response textEncodingName] forKey:@"textEncodingName"];

    // Decode:

 NSURL *url = [unarchiver decodeObjectForKey:@"URL"];
 NSString *mimeType = [unarchiver decodeObjectForIKey:@"MIMEType"];
 NSNumber *expectedContentLength = [unarchiver decodeObjectForKey:@"expectedContentLength"];
 NSString *textEncodingName = [unarchiver decodeObjectForKey:@"textEncodingName"];

 NSURLResponse* response = [[NSHTTPURLResponse alloc] initWithURL:url MIMEType:mimeType expectedContentLength:[expectedContentLength longLongValue] textEncodingName:textEncodingName];

Anyone know why this is? Is there a bug with archiving NSURLResponse or am I doing something wrong?

A: 

Memory management in Objective-C is as simple as knowing that any time you call something that has "alloc", "new", or "copy" in the method name (or if you retain it), then you must release it at some point. See this for more info: http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html

In your case, it appears that you call alloc to create an NSMutableData, but never release it (So [saveData release] at the end of doStuffWithResponse: may resolve at least one leak). From this code, this also appears to be the case with your alloc'ed NSKeyedUnarchiver and your alloc'ed NSURLResponse.

If you're not holding onto the value, like in an ivar, you can also just call autorelease right after alloc'ing, or use the class's autoreleased creators if available (e.g. [NSString stringWithFormat:] instead of [[NSString alloc] initWithFormat:]).

Selecting Build > Build and Analyze may also reveal such issues.

Jazon
That code is there actually, under the // release, clean up objects section. I didn't provide it to provide more focus on the exact spot causing leaks, but I guess it is causing more confusion. As I said, if I comment out the particular line of code, instruments reports zero leaks--the static analyzer also does not complain about simple leaks that that. I am releasing all of the objects I My question still stands.
Justin Ng