Asynchronous NSURLConnection Throws EXC_BAD_ACCESS

11,484

Solution 1

Use NSZombieEnabled break point and check which is the freed object.

Also check:

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    if ([response expectedContentLength] < 0)
    {
        NSLog(@"Connection error");
            //here cancel your connection.
            [connection cancel];
        return;
    }
}

Solution 2

I have followed the guidelines in Apple's documentation:

That is not true. In both of the following, you break the rules:

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

    // inform the user
    NSLog(@"Connection failed! Error - %@ %@",
          [error localizedDescription],
          [[error userInfo] objectForKey:NSErrorFailingURLStringKey]);
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    // do something with the data
    // receivedData is declared as a method instance elsewhere
    NSLog(@"Succeeded! Received %d bytes of data",[receivedData length]);

    // release the connection, and the data object
    [connection release];
    [receivedData release];
}

In both cases, you do not obtain the connection object with alloc, a method beginning with new or containing copy. You do not own connection in these methods. You must not release it in these methods.

It seems to me slightly dodgy that you are releasing receivedData there too. I suggest you immediately set the instance variable to nil after you release it.

[receivedData release];
receivedData = nil;

That way, it won't get accidentally released moere than once.

Solution 3

I got the same error when debugging with device although there was no problem in simulation. Adding the following line of code after releasing receivedData solved the problem:

receivedData = nil;

Solution 4

If you're getting the error on didRecieveData regardless of the code inside it, it looks like your delegate has been freed?

I'd check that the object that contains the getMessages method isn't being released (or autoreleased) before the connection has dfinished getting data.


EDIT: The comments below show that my above answer is wrong :)

The problem was in the recievedData variable - it was being released early. Mark suggests releasing it in the dealloc method of the object that creates the connection so he deserves all the credit for this!

There's one slight thing to lookout for there - if you release the recievedData in the dealloc method, you will leak memory if you call getMessages more than once. You will need to change getMessages slightly to this :

...
if (theConnection) {
    [recievedData release]; // If we've been here before, make sure it's freed.
    receivedData = [[NSMutableData data] retain];
} else {
...

Solution 5

Commenting on JeremyP, where he says that "In both of the following, you break the rules": Sheehan Alam is following Apple's code (actually, cut'n'paste) found here.

I'd also like to add (and this is something that wasn't well answered here) that the 'build and analyze' flags a "potential leak" on the NSURLConnection (which is initiated with a "[NSURLConnection alloc]"). But if one puts in a [theConnection release] on the NSURLConnection, in the same method, it will crash.

So we have something that seems to defy the 'rules' for memory management, yet works (afaik) and is in Apple's documentation..

Share:
11,484
Sheehan Alam
Author by

Sheehan Alam

iOS, Android and Mac Developer. i can divide by zero.

Updated on June 08, 2022

Comments

  • Sheehan Alam
    Sheehan Alam almost 2 years

    I'm not really sure why my code is throwing a EXC_BAD_ACCESS, I have followed the guidelines in Apple's documentation:

    -(void)getMessages:(NSString*)stream{
    
        NSString* myURL = [NSString stringWithFormat:@"http://www.someurl.com"];
    
        NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:myURL]];
    
        NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
        if (theConnection) {
            receivedData = [[NSMutableData data] retain];
        } else {
            NSLog(@"Connection Failed!");
        }
    
    }
    

    And my delegate methods

    #pragma mark NSURLConnection Delegate Methods
    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
    {
        // This method is called when the server has determined that it
        // has enough information to create the NSURLResponse.
    
        // It can be called multiple times, for example in the case of a
        // redirect, so each time we reset the data.
    
        // receivedData is an instance variable declared elsewhere.
        [receivedData setLength:0];
    }
    
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
    {
        // Append the new data to receivedData.
        // receivedData is an instance variable declared elsewhere.
        [receivedData appendData:data];
    }
    
    - (void)connection:(NSURLConnection *)connection
      didFailWithError:(NSError *)error
    {
        // release the connection, and the data object
        [connection release];
        // receivedData is declared as a method instance elsewhere
        [receivedData release];
    
        // inform the user
        NSLog(@"Connection failed! Error - %@ %@",
              [error localizedDescription],
              [[error userInfo] objectForKey:NSErrorFailingURLStringKey]);
    }
    
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection
    {
        // do something with the data
        // receivedData is declared as a method instance elsewhere
        NSLog(@"Succeeded! Received %d bytes of data",[receivedData length]);
    
        // release the connection, and the data object
        [connection release];
        [receivedData release];
    }
    

    I get an EXC_BAD_ACCESS on didReceiveData. Even if that method simply contains an NSLog, I get the error.

    Note: receivedData is an NSMutableData* in my header file

    • Mark
      Mark almost 14 years
      What is 'data' in the line that initialises your 'receivedData' variable?
  • Mark
    Mark almost 14 years
    Also, try to do nothing in the didRecieveData i.e. no lines of code, just an empty method, that will determine if its the delegate being released and not something else
  • Sheehan Alam
    Sheehan Alam almost 14 years
    even if didReceiveData contains no lines of code, I get the same error. The delegate is itself.
  • Mark
    Mark almost 14 years
    do the same with didReceiveResponse as well, see if that helps at all to narrow down the issue
  • Mark
    Mark almost 14 years
    perhaps call [self retain] just to make sure it doesnt get released??
  • Sheehan Alam
    Sheehan Alam almost 14 years
    zombie breakpoint says: *** -[NSConcreteMutableData length]: message sent to deallocated instance 0xd4af700 not sure how to diagnose...
  • Sheehan Alam
    Sheehan Alam almost 14 years
    I tried calling [self retain] before I init the request, same issue
  • Mark
    Mark almost 14 years
    that could be in the connectionDidFinishLoading method, try removing the code from that method too. if thats the problem your receivedData variable is the issue here...
  • Mark
    Mark almost 14 years
    yeah that was not a very good idea actually :) i feel that its your receivedData variable, try to remove the delegate methods one by one and see if you can isolate the error-some code
  • Sheehan Alam
    Sheehan Alam almost 14 years
    I commented out all code in connectionDidFinishLoading, and the app doesn't crash anymore. What do you think is wrong with receivedData?
  • Sheehan Alam
    Sheehan Alam almost 14 years
    Looks like the app doesn't crash when I comment out connectionDidFinishLoading. Any thoughts on what could be wrong with receivedData?
  • Mark
    Mark almost 14 years
    its not initialised, check to make sure that it is before you use it, and if it is not then create it.
  • Sheehan Alam
    Sheehan Alam almost 14 years
    Looks like I'm receiving the data, but my connection doesn't know when to stop. Where can I do this?
  • Sheehan Alam
    Sheehan Alam almost 14 years
    Looks like my connection is receiving data now, but because I commented out connectionDidFinishLoading where do I release?
  • Mark
    Mark almost 14 years
    you need to release at the point where you dont need the variable anymore and will not be making any server requests, perhaps in the dealloc method
  • Manjunath
    Manjunath almost 14 years
    @Sheehan Alam: tell me in which delegate your debugger stopped?
  • Manjunath
    Manjunath almost 14 years
    @Sheeham Alam: Dont release your NSURLConnection objects. There is an API called "cancel". Please change every releases to cancel. Just I showed you in my code example.
  • Sheehan Alam
    Sheehan Alam almost 14 years
    I changed my connection releases to cancels. My connectionDidFinishLoading method contains [connection cancel]; and [receivedData release]; However it looks like the connection isn't getting cancelled?
  • Manjunath
    Manjunath almost 14 years
    @Sheehan Alam: tell me exactly in which delegate your debugger stopped?
  • Sheehan Alam
    Sheehan Alam almost 14 years
    Thanks for the followup! I am curious where I need to release theConnection also?