views:

290

answers:

2

This piece of code:

- (IBAction) getXML {
    goButton.enabled = NO;
    [self performSelectorInBackground:@selector(parseInBackground) withObject:nil];
}

- (void)parseInBackground {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    xmlParser = [[XMLParser alloc] init];
    NSURL *xmlurl = [[NSURL alloc] initWithString:@"http://www.mysite.com/myfile.xml"];
    [xmlParser fetchXMLFromURL:xmlurl];
    [self performSelectorOnMainThread:@selector(didFinishXMLParsing) withObject:nil waitUntilDone:YES];
    [xmlurl release];
    [pool drain];
}

- (void)didFinishXMLParsing {
    goButton.enabled = YES;
}

triggers this code:

- (void)fetchXMLFromURL:(NSURL *)xmlurl {
    XMLData = [[NSMutableData alloc] init];

    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:xmlurl];

    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
    [connection release];
    [request release];

    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
}

However, when I step through it in debug, as soon as it gets to '}' in fetchXMLFromURL it returns to the line:

[self performSelectorOnMainThread:@selector(didFinishXMLParsing) withObject:nil waitUntilDone:YES];

and the connection to the URL which fetches the XML never actually gets triggered. Anyone any idea why?


This revised version seems to be working correctly, can anyone spot any potential issues?

- (void)fetchXMLFromURL:(NSURL *)xmlurl {
    XMLData = [[NSMutableData alloc] init];

    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
    XMLData = [NSData dataWithContentsOfURL:xmlurl];
    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];

    [self startParsingXML];
}

- (void) startParsingXML 
{ 
    NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithData:XMLData]; 
    xmlParser.delegate = self; 
    [xmlParser parse]; 
    [xmlParser release];
}

Revised again, hopefully correct now

- (void)fetchXMLFromURL:(NSURL *)xmlurl {

    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
    XMLData = [[NSData alloc] initWithContentsOfURL:xmlurl];
    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];

    [self startParsingXML];
}

- (void) startParsingXML 
{ 
    NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithData:XMLData]; 
    xmlParser.delegate = self; 
    [xmlParser parse]; 
    [xmlParser release];
}
+4  A: 

Yep. The NSURLConnection method you're using is asynchronous itself—it calls back to a couple of different delegate methods (as specified by the NSURLConnectionDelegate protocol) as it gets data. You might, in this case, be best off using the +sendSynchronousRequest:returningResponse:error: method, or NSData's +dataWithContentsOfURL:options:error:, as both of those will block execution on your background thread (which is fine) until they've finished getting your data. Also, make sure you set the network activity indicator's visibility before starting a synchronous request.

Noah Witherspoon
@Noah Witherspoon So in the original case, we get to the end of `fetchXMLFromURL` and terminate the thread, hence killing off the connection to the URL?
Griffo
Most likely, yeah.
Noah Witherspoon
Right, `fetchXMLFromURL:` returns immediately to `parseInBackground`. But see Rob Keniger's answer.
Sixten Otto
@Sixten Otto @Noah Witherspoon see update on question please
Griffo
Griffo: Currently you're allocating and initializing your `XMLData` object twice, and the first one is leaking. `+dataWithContentsOfURL:` returns an allocated, initialized, and autoreleased object for you. You probably want to remove that first line, and change the other one to `XMLData = [[NSData alloc] initWithContentsOfURL:xmlurl];`
Noah Witherspoon
Of course! It was very late at night when I altered the code, bleary eyes. I'll repost the modified code later, thanks so much @Noah Witherspoon
Griffo
+2  A: 

You're releasing the NSURLConnection as soon as you create it, which means it is immediately deallocated. You shouldn't release the NSURLConnection until you receive a delegate message that tells you the operation is complete, or has failed for some reason.

Rob Keniger
Ok but the release isn't a problem if I call `fetchXMLFromURL` without threading.
Griffo
@Rob Keniger see update on question please, thanks
Griffo