How to send request to server in background repeatedly? - iphone

In my application I need to send request to server to get xml after particular time interval say 1 hour to get the latest data.I want to perform this activity in background.Can anyone suggest how I can achieve this?
Thanks in advance!

Use NSTimer for repeatedly request and if u want to perform request in background thread u should do something like that:
backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler: ^{
[[UIApplication sharedApplication] endBackgroundTask:backgroundTask];
backgroundTask = UIBackgroundTaskInvalid;
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//start url request
});
//after url request complete
[[UIApplication sharedApplication] endBackgroundTask:backgroundTask];
backgroundTask = UIBackgroundTaskInvalid;

To solve above problem I created NSOperation to send request to server and parse response.Its very useful and better than using thread.
1.I created NSTimer instance which will call -(void)sendRequestToGetData:(NSTimer *)timer after particular time interval as follows:
//Initialize NSTimer to repeat the process after particular time interval...
NSTimer *timer = [NSTimer timerWithTimeInterval:60.0 target:self selector:#selector(sendRequestToGetData:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
2.Then inside sendRequestToGetData I created NSOperation by subclassing NSOperation as follows:
-(void)sendRequestToGetData:(NSTimer *)timer
{
//Check whether user is online or not...
if(!([[Reachability sharedReachability] internetConnectionStatus] == NotReachable))
{
NSURL *theURL = [NSURL URLWithString:myurl];
NSOperationQueue *operationQueue = [NSOperationQueue new];
DataDownloadOperation *operation = [[DataDownloadOperation alloc] initWithURL:theURL];
[operationQueue addOperation:operation];
[operation release];
}
}
Note: DataDownloadOperation is subclass of NSOperation.
//DataDownloadOperation.h
#import <Foundation/Foundation.h>
#interface DataDownloadOperation : NSOperation
{
NSURL *targetURL;
}
#property(retain) NSURL *targetURL;
- (id)initWithURL:(NSURL*)url;
#end
//DataDownloadOperation.m
#import "DataDownloadOperation.h"
#import "XMLParser.h"
#implementation DataDownloadOperation
#synthesize targetURL;
- (id)initWithURL:(NSURL*)url
{
if (![super init]) return nil;
self.targetURL = url;
return self;
}
- (void)dealloc {
[targetURL release], targetURL = nil;
[super dealloc];
}
- (void)main {
NSData *data = [NSData dataWithContentsOfURL:self.targetURL];
XMLParser *theXMLParser = [[XMLParser alloc]init];
NSError *theError = NULL;
[theXMLParser parseXMLFileWithData:data parseError:&theError];
NSLog(#"Parse data1111:%#",theXMLParser.mParsedDict);
[theXMLParser release];
}
#end

Related

How do I start an Asynchronous NSURLConnection inside an NSOperation?

I want to do an Asynchrous NSURLConnection inside of an NSOperation on a background thread.
it is because I'm doing some very expensive operations on the data as they come back.
This is a very similar question to what they asked here:
How do I do an Asynchronous NSURLConnection inside an NSOperation?
but the difference is that I run the connection in another class.
Here is my first attempt:
In my MainViewController:
#property (nonatomic, strong) NSOperationQueue *requestQueue;
#pragma mark - Lazy initialization
- (NSOperationQueue *)requestQueue
{
if (!_requestQueue) {
_requestQueue = [[NSOperationQueue alloc] init];
_requestQueue.name = #"Request Start Application Queue";
_requestQueue.maxConcurrentOperationCount = 1;
}
return _requestQueue;
}
-(void)callToServer
{
URLJsonRequest *request = [URLRequestFactory createRequest:REQUEST_INTERFACE_CLIENT_VERSION
delegate:self];
RequestSender *requestSender = [[RequestSender alloc]initWithPhotoRecord:request delegate:self];
[self.requestQueue addOperation:requestSender];
}
Here is my operation:
- (id)initWithPhotoRecord:(URLJsonRequest *)request
delegate:(id<RequestSenderDelegate>) theDelegate{
if (self = [super init])
{
self.delegate = theDelegate;
self.jsonRequest = request;
}
return self;
}
- (void)main {
//Apple recommends using #autoreleasepool block instead of alloc and init NSAutoreleasePool, because blocks are more efficient. You might use NSAuoreleasePool instead and that would be fine.
#autoreleasepool
{
if (self.isCancelled)
return;
[self.jsonRequest start];
}
}
Here is my Request start function:
-(void) start
{
NSURL *url = [NSURL URLWithString:#"http://google.com"];
NSURLRequest *theRequest = [NSURLRequest requestWithURL:url];
urlConnection = [[[NSURLConnection alloc] initWithRequest:theRequest delegate:self]autorelease];
[urlConnection start];
[theRequest release]
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
NSLog(#"Received reponse from connection");
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
}
I do not get a response from the server.
A couple of approaches:
Schedule the NSURLConnection in the main run loop, by using the startImmediately parameter of NO, set the run loop, and only then should you start the connection, e.g.:
urlConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self startImmediately:NO];
[urlConnection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
[urlConnection start];
Create a dedicated thread for the the connection and schedule the connection in the run loop you create for that thread. See AFURLConnectionOperation.m in AFNetworking source for an example of this.
Actually use AFNetworking, which gives you NSOperation based operations that you can add to your queue, and takes care of this run loop stuff for you.
So, AFNetworking does something like:
+ (void)networkRequestThreadEntryPoint:(id)__unused object {
#autoreleasepool {
[[NSThread currentThread] setName:#"NetworkingThread"];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
[runLoop run];
}
}
+ (NSThread *)networkRequestThread {
static NSThread *_networkRequestThread = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_networkRequestThread = [[NSThread alloc] initWithTarget:self
selector:#selector(networkRequestThreadEntryPoint:)
object:nil];
[_networkRequestThread start];
});
return _networkRequestThread;
}
So I do something like the following. First I have a few private properties:
#property (nonatomic, readwrite, getter = isExecuting) BOOL executing;
#property (nonatomic, readwrite, getter = isFinished) BOOL finished;
#property (nonatomic, weak) NSURLConnection *connection;
Then the network operation can then do something like:
#synthesize executing = _executing;
#synthesize finished = _finished;
- (instancetype)init {
self = [super init];
if (self) {
_executing = NO;
_finished = NO;
}
return self;
}
- (void)start {
if (self.isCancelled) {
[self completeOperation];
return;
}
self.executing = YES;
[self performSelector:#selector(startInNetworkRequestThread)
onThread:[[self class] networkRequestThread]
withObject:nil
waitUntilDone:NO];
}
- (void)startInNetworkRequestThread {
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:self.request
delegate:self
startImmediately:NO];
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[connection start];
self.connection = connection;
}
- (void)completeOperation {
self.executing = NO;
self.finished = YES;
}
- (void)setFinished:(BOOL)finished {
if (finished != _finished) {
[self willChangeValueForKey:#"isFinished"];
_finished = finished;
[self didChangeValueForKey:#"isFinished"];
}
}
- (void)setExecuting:(BOOL)executing {
if (executing != _executing) {
[self willChangeValueForKey:#"isExecuting"];
_executing = executing;
[self didChangeValueForKey:#"isExecuting"];
}
}
- (BOOL)isConcurrent {
return YES;
}
- (BOOL)isAsynchronous {
return YES;
}
// all of my NSURLConnectionDataDelegate stuff here, for example, upon completion:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// I call the appropriate completion blocks here, do cleanup, etc. and then, when done:
[self completeOperation];
}
-(void)start
{
[self willChangeValueForKey:#"isExecuting"];
_isExecuting = YES;
[self didChangeValueForKey:#"isExecuting"];
NSURL* url = [[NSURL alloc] initWithString:#"http://url.to/feed.xml"];
NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20];
_connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; // ivar
[request release];
[url release];
// Here is the trick
NSPort* port = [NSPort port];
NSRunLoop* rl = [NSRunLoop currentRunLoop]; // Get the runloop
[rl addPort:port forMode:NSDefaultRunLoopMode];
[_connection scheduleInRunLoop:rl forMode:NSDefaultRunLoopMode];
[_connection start];
[rl run];
}
More details can be found here: link
I know this post is over a year old, but I wanted to add some suggestions for people who may run the same problem trying to create own async network operation.
You need to add runloop to operation that runs in background and you should stop it when the operations has finished.
There actually 2 simple options:
Option 1 - using NSRunLoop
NSPort *port = [NSPort port];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:port forMode:NSDefaultRunLoopMode];
[self.connection scheduleInRunLoop:runLoop forMode:NSDefaultRunLoopMode];
[self.connection start];
[runLoop run];
and you need to stop when the operation is finished:
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
NSDate *date = [NSDate distantFuture];
while (!runLoopIsStopped && [runLoop runMode:NSDefaultRunLoopMode beforeDate:date]);
Option 2 - using CF
You need to add
CFRunLoopRun();
when you start operation
and call
CFRunLoopStop(CFRunLoopGetCurrent());
when you finish operation.
Read the following post: CFRunLoopRun() vs [NSRunLoop run]

iPhone timer task for long processes

When the application enters into background state, the time used to run in background is not working. Following is the code.
In AppDelegate.h,
#interface AppDelegate : UIResponder <UIApplicationDelegate>
{
BOOL status;
UIBackgroundTaskIdentifier bgTask;
}
In AppDelegate.m
- (void)applicationDidEnterBackground:(UIApplication *)application
{
NSAssert(self->bgTask == UIBackgroundTaskInvalid, nil);
bgTask = [application beginBackgroundTaskWithExpirationHandler: ^{
dispatch_async(dispatch_get_main_queue(), ^{
[application endBackgroundTask:self->bgTask];
self->bgTask = UIBackgroundTaskInvalid;
});
}];
dispatch_async(dispatch_get_main_queue(), ^{
if ([application backgroundTimeRemaining] > 1.0) {
// Start background service synchronously
[[vController getInstance] run];
}
[application endBackgroundTask:self->bgTask];
self->bgTask = UIBackgroundTaskInvalid;
});
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
NSAssert(self->bgTask == UIBackgroundTaskInvalid, nil);
bgTask = [application beginBackgroundTaskWithExpirationHandler: ^{
dispatch_async(dispatch_get_main_queue(), ^{
[application endBackgroundTask:self->bgTask];
self->bgTask = UIBackgroundTaskInvalid;
});
}];
dispatch_async(dispatch_get_main_queue(), ^{
if ([application backgroundTimeRemaining] > 1.0) {
// Start background service synchronously
[[vController getInstance] stopbackground];
}
[application endBackgroundTask:self->bgTask];
self->bgTask = UIBackgroundTaskInvalid;
});
}
And in view Controller.h,
#interface vController : UIViewController <AVAudioPlayerDelegate>
-(void) run;
-(void) stopbackground;
-(void) getMessage:(NSTimer*)theTimer;;
+(vController*) getInstance;
#property (nonatomic,retain) NSTimer * timer;
#end
the view controller.m,
#implementation vController
#synthesize timer;
vController *tvc;
- (void)viewDidLoad
{
[super viewDidLoad];
tvc = self;
// Do any additional setup after loading the view, typically from a nib.
}
+ (vController*) getInstance
{
return tvc;
}
- (void)stopbackground
{
timer = [NSTimer scheduledTimerWithTimeInterval:15.0 target:self selector:#selector(getMessage:) userInfo:nil repeats:YES];
}
- (void)run
{
timer = [NSTimer scheduledTimerWithTimeInterval:15.0 target:self selector:#selector(getMessage:) userInfo:nil repeats:YES];
}
- (void) getMessage:(NSTimer*) theTimer
{
NSError *error;
NSString *path = [[NSBundle mainBundle] pathForResource:#"alert" ofType:#"mp3"];
AVAudioPlayer* theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];
if (theAudio == nil) {
NSLog(#"%#", [error description]);
}
NSLog(#"Hi");
theAudio.delegate = self;
theAudio.numberOfLoops = 1;
[theAudio play];
}
- (void) dealloc{
[timer release];
[super dealloc];
}
I am using it on simulator 6.0
Depending on your use case, this may not be possible. Namely, Apple does not let you execute code in the 'background' unless you are performing one of the following tasks:
Apps that play audible content to the user while in the background,
such as a music player app
Apps that keep users informed of their location at all times, such as a navigation app
Apps that support Voice over Internet Protocol (VoIP)
Newsstand apps that need to download and process new content
Apps that receive regular updates from external accessories
Read more at :http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html
By Creating Instance you can Run Background Task in Any View-controller like Below:
// Declare the following in YourViewController.h file.
+ (YourViewController *)getInstance;
- (void)run;
-(void)stopbackground;
// Define the Vollowing in YourViewController.m file.
static YourViewController *instance = NULL;
+(YourViewController *)getInstance {
#synchronized(self) {
if (instance == NULL) {
instance = [[self alloc] init];
}
}
return instance;
}
- (void)run
{
// strat Back ground task
}
-(void)stopbackground
{
// Stop Background task
}
in AppDelegate.h file Declare the Following
UIBackgroundTaskIdentifier bgTask;
in AppDelegate.m file use the Following Methods.
- (void)applicationDidEnterBackground:(UIApplication *)application {
NSLog(#"Application entered background state.");
// bgTask is instance variable
NSAssert(self->bgTask == UIBackgroundTaskInvalid, nil);
bgTask = [application beginBackgroundTaskWithExpirationHandler: ^{
dispatch_async(dispatch_get_main_queue(), ^{
[application endBackgroundTask:self->bgTask];
self->bgTask = UIBackgroundTaskInvalid;
});
}];
dispatch_async(dispatch_get_main_queue(), ^{
if ([application backgroundTimeRemaining] > 1.0) {
// Start background service synchronously
[[YourViewController getInstance] run];
}
[application endBackgroundTask:self->bgTask];
self->bgTask = UIBackgroundTaskInvalid;
});
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
NSLog(#"Application entered background state.");
// bgTask is instance variable
NSAssert(self->bgTask == UIBackgroundTaskInvalid, nil);
bgTask = [application beginBackgroundTaskWithExpirationHandler: ^{
dispatch_async(dispatch_get_main_queue(), ^{
[application endBackgroundTask:self->bgTask];
self->bgTask = UIBackgroundTaskInvalid;
});
}];
dispatch_async(dispatch_get_main_queue(), ^{
if ([application backgroundTimeRemaining] > 1.0) {
// Start background service synchronously
[[YourViewController getInstance] stopbackground];
}
[application endBackgroundTask:self->bgTask];
self->bgTask = UIBackgroundTaskInvalid;
});
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}

Can we thread the web-service and insert in in custom table cell?

The thing is i have to make Custom cell of UITable, i have to call large webservice with many data which will take longer tym to load it once. So i want to apply threading in it. now my que is. can we at run -time insert value one by one in custom cell , as user will see data comming one by one at run time..?? if yes how we can do that.
yes you can ... try this
- (void)viewDidLoad
{
myApp = (myAppDelegate *) [[UIApplication sharedApplication] delegate];
[self performSelectorInBackground:#selector(startParsing) withObject:nil];
[super viewDidLoad];
}
- (void) startParsing
{
[self performSelectorOnMainThread:#selector(startIndicator) withObject:nil waitUntilDone:NO];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSURL *url = [[NSURL alloc] initWithString:#"http://abc.com"];
NSData *data = [NSData dataWithContentsOfURL:url];
// 2 -- parsing
parser = [[VolMyParser alloc] init];
[parser parseXML:data];
[data release];
//[parser print];
[self performSelectorOnMainThread:#selector(updateTable) withObject:nil waitUntilDone:NO];
[pool release];
}
- (void) startIndicator
{
av.hidesWhenStopped = YES;
[av startAnimating];
}
- (void) updateTable
{
[av stopAnimating];
[myTable reloadData];
}
Hope its gives you an Idea...

xml parsing consumes time need efficent way on iphone

How to call main thread ??? i can parse but i cant display data
- (void)viewDidLoad {
//self.navigationItem.rightBarButtonItem = self.editButtonItem;
self.parentViewController.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"10.png"]];
[super viewDidLoad];
[NSThread detachNewThreadSelector:#selector(startTheBackgroundJob) toTarget:self withObject:nil];
}
- (void)startTheBackgroundJob {
NSUserDefaults *getida = [NSUserDefaults standardUserDefaults];
myIDa = [getida stringForKey:#"AppID"];
NSLog(#"#BOOK MARK ");
NSString *ubook = [[NSString alloc] initWithFormat:#"http://www.wapp=%#&action=show",myIDa];
NSLog(#" bookmark %#",ubook);
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
//NSString *outputString = [[NSString stringWithString:usearch] stringByAppendingString: UserText];
ubook = [ubook stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(#"My string is now = %#", ubook);
NSURL *url = [[[NSURL alloc] initWithString:ubook]autorelease];
//NSURL *url= [NSURL URLWithString:outputString];
NSLog(#" bookmark URL IS %#",url);
NSXMLParser *xmlParser = [[[NSXMLParser alloc] initWithContentsOfURL:url] autorelease];
//Initialize the delegate.
XMLParserbookm *parser = [[[XMLParserbookm alloc] initXMLParser]autorelease];
//Set delegate
[xmlParser setDelegate:parser];
//Start parsing the XML file.
BOOL success = [xmlParser parse];
if(success)
{
NSLog(#" xml parsed suucess");
//[super viewDidLoad];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
//[self searchTableView];
//mytimer4=[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(wipe) userInfo:nil repeats:NO];
}
else{
NSLog(#"eeror");
}
[NSThread sleepForTimeInterval:3];
[self performSelectorOnMainThread:#selector(makeMyProgressBarMoving) withObject:nil waitUntilDone:NO]; // HOW TO CALL MAIN THREAD
[pool release]
}
You can try with
viewDidAppear:, this method is called after you go to a new view. Then at least, you can switch to new view, you should make sure that there is something on the screen in waiting for the xml parsing
Using Thread: You put parsing into another thread and then callback your main thread after you finish, then there will be no block at all

How do I do an Asynchronous NSURLConnection inside an NSOperation?

I want to do an Asynchrous NSURLConnection inside of an NSOperation on a background thread.
(it is because I'm doing some very expensive operations on the data as they come back that want to be done as the data comes in and in background)
Here is my first attempt:
IN my AppDelegate:
// create the opperation and add it to the queue:
self.sharedOperationQueue = [[[NSOperationQueue alloc] init] autorelease];
LibXMLOperation *op = [[[LibXMLOperation alloc] init] autorelease];
[self.sharedOperationQueue addOperation:op];
Here is my operation:
#interface EbirdLibXMLOperation : NSOperation {
#private
NSURLConnection *urlConnection;
// Overall state of the parser, used to exit the run loop.
BOOL done;
// properties to maintain the NSOperation
BOOL finished;
BOOL executing;
}
- (void)downloadAndParse:(NSURL *)url;
- (void)start;
- (BOOL)isConcurrent;
- (BOOL)isFinished;
- (BOOL)isExecuting;
#property BOOL done;
#property (nonatomic, retain) NSURLConnection *ebirdConnection;
// The autorelease pool property is assign because autorelease pools cannot be retained.
#property (nonatomic, assign) NSAutoreleasePool *downloadAndParsePool;
#end
#implementation LibXMLOperation
#synthesize urlConnection, done;
- (void)start{
if (![self isCancelled]) {
[self willChangeValueForKey:#"isExecuting"];
executing = YES;
//set up the thread and kick it off...
[[NSURLCache sharedURLCache] removeAllCachedResponses];
NSURL *url = [NSURL URLWithString:#"http://google.com"];
[NSThread detachNewThreadSelector:#selector(downloadAndParse:) toTarget:self withObject:url];
[self didChangeValueForKey:#"isExecuting"];
} else {
// If it's already been cancelled, mark the operation as finished.
[self willChangeValueForKey:#"isFinished"];
finished = YES;
[self didChangeValueForKey:#"isFinished"];
}
}
- (BOOL)isConcurrent {
return YES;
}
- (BOOL)isExecuting {
return executing;
}
- (BOOL)isFinished {
return finished;
}
- (void)downloadAndParse:(NSURL *)url {
self.downloadAndParsePool = [[NSAutoreleasePool alloc] init];
done = NO;
self.characterBuffer = [NSMutableData data];
[[NSURLCache sharedURLCache] removeAllCachedResponses];
NSURLRequest *theRequest = [NSURLRequest requestWithURL:url];
urlConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (urlConnection != nil) {
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (!done);
}
[self willChangeValueForKey:#"isFinished"];
[self willChangeValueForKey:#"isExecuting"];
finished = YES;
executing = NO;
// Clean up.
self.urlConnection = nil;
[downloadAndParsePool release];
NSLog(#"download and parse cleaning up");
self.downloadAndParsePool = nil;
[self didChangeValueForKey:#"isExecuting"];
[self didChangeValueForKey:#"isFinished"];
}
#pragma mark NSURLConnection Delegate methods
// Disable caching so that each time we run this app we are starting with a clean slate.
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {
return nil;
}
// Forward errors to the delegate.
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
done = YES;
}
// Called when a chunk of data has been downloaded.
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Process the downloaded chunk of data.
NSLog(#"Did received %i bytes", [data length]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// Set the condition which ends the run loop.
done = YES;
}
#end
When this runs, I see the following message in my log:
2009-08-20 15:18:48.858 App[1001:3e03]*** _NSAutoreleaseNoPool(): Object 0x1126a20 of class NSCFArray autoreleased with no pool in place - just leaking
Stack: (0x305a2e6f 0x30504682 0x3057deba 0x305ced09 0x30577ddf 0x3056b43e 0x3050764a 0x58fc3 0x3050a79d 0x3050a338 0x94568155 0x94568012)
This event happens at the very last [self didChangeValueForKey:#"isFinished"]; which suggests to me that I'm setting up the NSOperation wrong.
Move the lines:
[downloadAndParsePool release];
self.downloadAndParsePool = nil;
to the end of the -downloadAndParse: method.