Asynchronous NSURLConnection Throws EXC_BAD_ACCESS

2019-02-07 05:53发布

问题:

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

回答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;
    }
}


回答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.



回答3:

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 {
...


回答4:

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;


回答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..



回答6:

I got EXC_BAD_ACCESS on Asynchronous call at NSURLConnection. The code is generated by http://www.sudzc.com

I needed to add a retain to

receivedData = [[NSMutableData data] retain];

and the callback methods doesn't get bad access signal anymore.

  • if I add the

    if ([response expectedContentLength] < 0) { NSLog(@"Connection error"); //here cancel your connection. [connection cancel]; return; }

than all my webservices are canceled, otherwise works perfectly.



回答7:

While it doesn't answer the full question, I've run into this error a couple of times because I set the request's HTTPBody to an NSString instead of a NSData. Xcode tried to warn me.