views:

2226

answers:

2

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  A: 

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.

h4xxr
While calling autorelease will work, it will fail in the cases where the delegate is released before the connection is released. The better way would be to assign the connection to an instance variable and release+nil it when not needed. If the connection ivar is still assigned when the object deallocs, the delegate needs to be set to nil before releasing the connection.
rpetrich
@rpetrich I agree your suggestion is more comprehensive, however it was clear that his question showed a basic misunderstanding of memory management on iPhone and therefore I wanted to give him a conceptually easier solution
h4xxr
@rpetrich, can you provide a code example. I've tried to solve this problem in many ways and still have a leak.
Jordan
@rpetrich, yes i would like to see your example as well.
vicky
A: 

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.

William Denniss
for the record, I switched to the autorelease'd [NSURLConnection connectionWithRequest:request delegate:self] but I don't think it should matter.
William Denniss