Slowburner
Slowburner

Reputation: 183

iPhone App Crashes with dispatch_async if operation is not completed

In my shipping iPhone App, I've used a dispatch_async block without issues. The App checks a web site for price updates, parses the HTML, updates a Core Data model accordingly, and then refreshes the table being viewed.

In my latest App however, I've found I can crash the App by switching out of the App while the price update process is running. The differences between the first and second usage seem to me to be only that I'm calling the dispatch block from the table's refreshController (ie. tableViewController's now built-in pull-to-refresh mechanism) and that this is now iOS7.

Can anyone suggest to me how dispatch_async should be gracefully aborted under known conditions, such as the user wishing to stop the process, or if they switch apps like this and I'd like to intercept that activity to manage the block properly, please?

If there's any good background reading on do's and don'ts with blocks, I'd be pleased to look through such links likewise - thanks!

This is the (mostly boilerplate) dispatch_async code I'm using, for your convenience:

priceData = [[NSMutableData alloc]init];     // priceData is declared in the header
priceURL = …     // the price update URL

NSURL *requestedPriceURL = [[NSURL alloc]initWithString:[@“myPriceURL.com”]];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:requestedPriceURL];

dispatch_queue_t dispatchQueue = dispatch_queue_create("net.fudoshindesign.loot.priceUpdateDispatchQueue", NULL);   //ie. my made-up queue name
dispatch_async(dispatchQueue, ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            NSURLConnection *conn = [[NSURLConnection alloc]initWithRequest:urlRequest delegate:self startImmediately:YES];
            [conn start];
        })
});

Upvotes: 2

Views: 3068

Answers (3)

Salman Zaidi
Salman Zaidi

Reputation: 9842

Although you have a async block but you are executing NSURLConnection Request on main thread in that block, that's why app gets crashed if process doesn't get completed. Execute request in background thread. You are blocking main thread in this code.

You can do it like this:

dispatch_queue_t dispatchQueue = dispatch_queue_create("net.fudoshindesign.loot.priceUpdateDispatchQueue", 0);   //ie. your made-up queue name
dispatch_async(dispatchQueue, ^{
        NSURLConnection *conn = [[NSURLConnection alloc]initWithRequest:urlRequest delegate:self startImmediately:YES];
        [conn start];
        ...
        //other code
        ...
        dispatch_async(dispatch_get_main_queue(), ^{
            //process completed. update UI or other tasks requiring main thread   
        });
    });

try reading and practicing more about GCD.

Grand Central Dispatch (GCD) Reference from Apple Docs

GCD Tutorial

Upvotes: 2

gnasher729
gnasher729

Reputation: 52530

That boilerplate code looks quite useless.

You create a serial queue. You dispatch a block on the queue which does nothing but dispatching a block on the main queue. You might as well have dispatched on the main queue directly.

Upvotes: 2

Rafał Sroka
Rafał Sroka

Reputation: 40030

There's no explicit provision in dispatch queues for cancelling. Basically, it would be a semaphore.

NSOperationQueue (a higher level abstraction, but still built using GCD underneath) has support for canceling operations. You can create a series of NSOperations and add them to an NSOperationQueue and then message cancelAllOperations to the queue when you don't need it to complete.

Useful link:

http://www.cimgf.com/2008/02/16/cocoa-tutorial-nsoperation-and-nsoperationqueue/

Dispatch queues: How to tell if they're running and how to stop them

Upvotes: 0

Related Questions