5

CSURLCache is designed to cache resources for offline browsing, as NSURLCache only stores data in-memory.

If cachedResponse is autoreleased before returning the application crashes, if not, the objects are simply leaked.

Any light that could be shed onto this would be much appreciated.

Please note stringByEncodingURLEntities is a category method on NSString.

@interface CSURLCache : NSURLCache {} @end

@implementation CSURLCache

- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request
{
    NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[[[request URL] absoluteString] stringByEncodingURLEntities]];

    if ([[NSFileManager defaultManager] fileExistsAtPath:path])
    {
        NSData *data = [[NSData alloc] initWithContentsOfFile:path];
        NSURLResponse *response = [[NSURLResponse alloc] initWithURL:[request URL]
                                                            MIMEType:nil
                                               expectedContentLength:[data length]
                                                    textEncodingName:nil];

        NSCachedURLResponse *cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response
                                                                                       data:data];
        [response release];
        [data release];

        return cachedResponse;
    }

    return nil;
}

@end

UPDATE: After submitting a radar to Apple it appears that this is a known issue (Radar #7640470).

Oliver White
  • 265
  • 2
  • 9
  • Are you sure they're leaked if they aren't autoreleased? And are you sure your program crashes because you attempt to release them? Memory management rules clearly states you'd be the one responsible for releasing that object. – zneak Jan 29 '10 at 01:06
  • 3
    Yes, they are definitely leaking if not autoreleased. The program crashes because a retain message is sent to a deallocated object – Oliver White Jan 29 '10 at 12:26

1 Answers1

1
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request

Well, this isn't an alloc, new, or copy method…

… and CSURLCache doesn't hold on to the object anywhere, so it's not owning it.

So, you need to autorelease it.

Of course, that means the object is doomed unless something retains it. Your app crashed because it tried to use the object after the object died.

Run your app under Instruments with the Zombies template. Look at where the app crashes and what it was doing when cachedResponseForRequest: was called. The caller needs to own the object until the time when the application would crash otherwise, and then release it.

Peter Hosey
  • 95,783
  • 15
  • 211
  • 370
  • The app crashes because a retain message is sent to a deallocated object, though, with subsequent investigation, NOT the cachedResponse. I cannot however figure out which object is being sent the message. If I enable NSZombieEnabled it prints "[Not A Type retain]". – Oliver White Jan 29 '10 at 12:29
  • Don't believe this to be the solution, as the NSCachedResponse isn't the object that is causing the crash when it is released (it's crashing as part of it's dealloc, meaning something that NSCachedResponse is retaining is overreleased) – BadPirate Aug 30 '10 at 20:22
  • outtru.mp: Implementing memory management correctly isn't optional (not doing so would mean the questioner would have two bugs), and the Zombies instrument is how you would determine what object is over-released and what the extraneous release was. So, the former aspect is part of the solution (leaking may be preferable to a crash, but once the crash is eliminated, the leak should be, too), and the latter is part of the investigation of the real problem. – Peter Hosey Aug 30 '10 at 22:18