简体   繁体   中英

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];
        })
});

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.

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM