NSURLConnection leak?

2019-01-22 00:36发布

问题:

i have set up a nsurl which grabs the data from http. when i run instrument, it says i have a leak NSFNetwork object.

and how do i release theConnection in (void)ButtonClicked? or it will be release later on?

- (void)ButtonClicked {
    NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:KmlUrl]
                                                cachePolicy:NSURLRequestUseProtocolCachePolicy
                                            timeoutInterval:20.0f];

    NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
    if (theConnection) {
        // receivedData is declared as a method instance elsewhere
        NSMutableData *receivedData = [[NSMutableData data] retain];
        [self setKMLdata:receivedData];
    } else {
        // inform the user that the download could not be made
    }
}


- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    // append the new data to the receivedData
    // receivedData is declared as a method instance elsewhere
    [KMLdata appendData:data];
    NSLog(@"didReceiveData");
}


- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    // release the connection, and the data object
    [connection release];
    [KMLdata release];
}


- (void)connection:(NSURLConnection *)connection  didFailWithError:(NSError *)error
{
    // release the connection, and the data object
    [connection release];
    // receivedData is declared as a method instance elsewhere
    [KMLdata release];

}

回答1:

I finally found the answer for this.

The error in the above code (which by the way is the near-exact sample from the SDK docs) is not in the memory management code. Autorelease is one option, manual release is another. Regardless of how you handle your NSURLConnection object, you get leaks using NSURLConnection.

First up, here is the solution. Just copy these 3 lines of code directly into connectionDidFinishLoading, didFailWithError and anywhere else you release the NSURLConnection object.

NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil];
[NSURLCache setSharedURLCache:sharedCache];
[sharedCache release];

Credit to mpramodjain on http://forums.macrumors.com/showthread.php?t=573253 for the code.

The problem seems to be this – the SDK caches the requests and replies on the iPhone. Even it seems if your NSMutableURLRequest cachePolicy is set to not load the reply from the cache.

The silly thing is that it seems to cache a lot of data by default. I'm transmitting a lot of data (split into multiple connections) and started to get memory warnings, and finally my App died.

The docs we need are in NSURLCache (not NSURLConnection), they state:

NSURLCache implements the caching of responses to URL load requests by mapping NSURLRequest objects to NSCachedURLResponse objects. It is a composite of an in-memory and an on-disk cache.

Methods are provided to manipulate the sizes of each of these caches as well as to control the path on disk to use for persistent storage of cache data.

Those three lines have the effect of nuking the cache totally. After adding them to my App (GPS Log), my #living object count remains steady.



回答2:

Hello have you test this delegate method ?

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
    return nil;
}

You can manage the cache more precisely.

"reset" NSURLCache *sharedCache can cause problems on other part of your code ?



回答3:

This is a common question and is solved by the magic of [object autorelease]. In your code this would be as follows:

NSURLConnection *theConnection = [[[NSURLConnection alloc] initWithRequest:theRequest delegate:self] autorelease];

In this way, the object is automatically added to the "autorelease pool" and dealloc'd at the start of the next run loop after it is no longer referenced.

Hope that helps

Edit: Also, I don't see why you're needing to call -retain on your receivedData variable.



回答4:

I am using the static method/autoreleased approach and it appears to work fine:

[NSURLConnection connectionWithRequest:theRequest delegate:self];

This way you don't even have to worry about releasing in the delegate callbacks. It turns out that the retain count of the connection is actually 2 (not 1) after it is alloc'd in the examples above, which changes the way I thought about this memory "leak."

@rpetrich I actually don't think you need to worry about the delegate being released before the connection is released. The connection retains it's delegate and the connection itself is actually retained by some sort of open connections queue. I wrote a blog post on my experiments with NSURLConnection on my blog:

"Potential leak of object" with NSURLConnection