views:

892

answers:

3

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

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 {
...
deanWombourne
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
Mark
even if didReceiveData contains no lines of code, I get the same error. The delegate is itself.
Sheehan Alam
do the same with `didReceiveResponse` as well, see if that helps at all to narrow down the issue
Mark
same results when didReceiveResponse contains no code
Sheehan Alam
perhaps call [self retain] just to make sure it doesnt get released??
Mark
I tried calling [self retain] before I init the request, same issue
Sheehan Alam
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
Mark
Looks like the app doesn't crash when I comment out connectionDidFinishLoading. Any thoughts on what could be wrong with receivedData?
Sheehan Alam
its not initialised, check to make sure that it is before you use it, and if it is not then create it.
Mark
Looks like my connection is receiving data now, but because I commented out connectionDidFinishLoading where do I release?
Sheehan Alam
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
Mark
Thanks for the followup! I am curious where I need to release theConnection also?
Sheehan Alam
+2  A: 

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;
    }
}
Manjunath
zombie breakpoint says: *** -[NSConcreteMutableData length]: message sent to deallocated instance 0xd4af700 not sure how to diagnose...
Sheehan Alam
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
I commented out all code in connectionDidFinishLoading, and the app doesn't crash anymore. What do you think is wrong with receivedData?
Sheehan Alam
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: tell me in which delegate your debugger stopped?
Manjunath
@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.
Manjunath
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?
Sheehan Alam
@Sheehan Alam: tell me exactly in which delegate your debugger stopped?
Manjunath
+2  A: 

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.

JeremyP