Asynchronous Loading of Image - Crashing If Dealloced
I have a UIViewController presented by a navigation controller. This UIViewController loads an image asynchronously as follows :
[self performSelectorInBackground:@selector(downloadData) withObject:nil];
- (void)downloadData {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
LocationDet开发者_如何学JAVAails * details = [[LondonDatabase database] locationDetails : UniqueID];
NSData * imageData = [NSData dataWithContentsOfURL : [NSURL URLWithString : [details image]]];
picture = [[UIImage alloc ]initWithData:imageData];
[self performSelectorOnMainThread : @selector(updateUI) withObject : nil waitUntilDone : NO];
[pool release];
}
The problem is that if this view controller is popped off the stack while the above method is executing the app crashes with the error :
bool _WebTryThreadLock(bool), 0x61b3950: 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...
Can anyone help ?
Thanks,
Martin
Use an NSThread and keep a handle to that in the view controller object. When the view controller dealloc's, cancel the thread (assuming it has not completed). In downloadData, check that the thread isn't cancelled before trying to access elements of the view controller. That is to say, if the thread has been cancelled, just return. I had a similar issue and this is how I solved it.
Here's the code (which was loading an image into a custom table cell):
-(void)displayImage:(id)context { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; UIImage *image = (UIImage *)context; [spinner stopAnimating]; brandImage.image = image; [brandImage setNeedsDisplay]; [pool release]; } -(void)fetchImage:(id)context { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSString *url = (NSString *)context; if ([[NSThread currentThread] isCancelled]) return; UIImage *image = [ArtCache imageForURL:url]; if (![[NSThread currentThread] isCancelled]) { [self performSelectorOnMainThread:@selector(displayImage:) withObject:image waitUntilDone:NO]; } [pool release]; } -(void)showBrandImageURL:(NSString *)url { [spinner startAnimating]; brandImage.image = nil; if (imageLoadThread) { [imageLoadThread cancel]; [imageLoadThread release]; } imageLoadThread = [[NSThread alloc] initWithTarget:self selector:@selector(fetchImage:) object:url]; [imageLoadThread setThreadPriority:0.8]; [imageLoadThread start]; }
These were 3 methods in the custom table cell class. The last one was the one called from cellForRowAtIndexPath:
. The other two support the one that is called.
精彩评论