Updating a deallocated UIWebView from a background thread

Posted by Dan Ray on Stack Overflow See other posts from Stack Overflow or by Dan Ray
Published on 2010-06-07T20:54:46Z Indexed on 2010/06/07 22:52 UTC
Read the original article Hit count: 396

As you can see from the title, I've programmed myself into a corner and I've got several things working against me...

In a UIViewController subclass that manages a large and complex view. One part of it is a UIWebView that contains output from a web request that I had to build and execute, and manually assemble HTML from. Since it takes a second or two to run, I dropped it into the background by calling self performSelectorInBackground:. Then from that method I call there, I use self performSelectorOnMainThread: to get back to the surface of the thread stack to update the UIWebView with what I just got.

Like this (which I've cut down to show only the relevant issues):

-(void)locationManager:(CLLocationManager *)manager
   didUpdateToLocation:(CLLocation *)newLocation
          fromLocation:(CLLocation *)oldLocation
{
    //then get mapquest directions
    NSLog(@"Got called to handle new location!");

    [manager stopUpdatingLocation];

    [self performSelectorInBackground:@selector(getDirectionsFromHere:) withObject:newLocation];

}

- (void)getDirectionsFromHere:(CLLocation *)newLocation
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    CLLocationCoordinate2D here = newLocation.coordinate;

 // assemble a call to the MapQuest directions API in NSString *dirURL
 // ...cut for brevity

    NSLog(@"Query is %@", dirURL);
    NSString *response = [NSString stringWithContentsOfURL:[NSURL URLWithString:dirURL] encoding:NSUTF8StringEncoding error:NULL];
    NSMutableString *directionsOutput = [[NSMutableString alloc] init];

// assemble response into an HTML table in NSString *directionsOutput
// ...cut for brevity

    [self performSelectorOnMainThread:@selector(updateDirectionsWithHtml:) withObject:directionsOutput waitUntilDone:NO];
    [directionsOutput release];
    [pool drain];
    [pool release];
}


- (void)updateDirectionsWithHtml:(NSString *)directionsOutput
{
    [self.directionsWebView loadHTMLString:directionsOutput baseURL:nil];
}

This all works totally great, UNLESS I've backed out of this view controller before CLLocationManager hits its delegate method. If this happens after I've already left this view, I get:

2010-06-07 16:38:08.508 EverWondr[180:760b] bool _WebTryThreadLock(bool), 0x1b6830: Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...

Despite what this says, I can repeatably cause this crash when I back out too early. I'm not at all convinced that attempting a UI update from a background thread is really the issue; I think it's that my UIWebView is deallocated. I suspect that the fact I was just IN a background thread makes the runtime suspect something's up about that, but I feel fairly sure that's not it.

So how do I tell CLLocationManager not to worry about it, when I'm backing out of that view? I tried [self.locationManager stopUpdatingLocation] inside my viewWillDisappear method, but that didn't do it.

(Incidentally, MapQuest's apis are FANTASTIC. Way WAY better than anything Google provides. I can't recommend them highly enough.)

© Stack Overflow or respective owner

Related posts about iphone

Related posts about memory-management