views:

426

answers:

2

Hi there,

I'm about to create a series of NSOperations and run them in a queue.

They will all be sequential and run one at a time.

These operations will fetch data from the web and create and save core data managed objects.

How do I handle the situation where the application exits? As the operations run in detached threads, how can I make the main thread wait until the current operation is "safe" to quit? There are situations where I'm happy for the threads (operations) to exit before they are complete as on further app launches the job will continue and pick up where it left off.

Many thanks,

Mike

+1  A: 

Your app will be forced to quit if it won't quit by itself for a specified time. So waiting for some data to come stumbling in from the internet might not be a good idea.

But you already gave yourself the answer. Just make the operations atomic by design. What I mean with this is that your operations should either complete the job (download + save of data) or you run it again on next startup. Make sure that all temp data of a job is rolled back if the did app quit before the job completed.

sliver
So, if I tell the operation queue to cancel all operations on applicationWillTerminate, how can I get the main thread to wait until the canceled operations have completed cancelling (i.e. the current operation thread completed rolling everything back and cleaning up)?
Michael Waterfall
You can't You can try, but it's not guaranteed. As noted, do what you can and make all operations atomic in nature (atomic writes are an option when writing out new files, it first writes out contents in a temp file and then renames it if that completes)
Kendall Helmstetter Gelner
I would not rollback changes when the application quits. Instead do the rollback on next application start.
sliver
+1  A: 

Design your operations so that they check their isCancelled property at appropriate safe times (at start, after one stage of the operation has completed, etc.) and bail out at that point. In applicationWillTerminate, send your operation queue a -cancelAllOperations message, and follow that up with a -waitUntilAllOperationsAreFinished message. This will block until all operations in the queue have completed. This shouldn't slow your application exit much if all of the operations handle isCancelled properly.

One thing to watch out for is the fact that -waitUntilAllOperationsAreFinished, when called from applicationWillTerminate, will block on the main thread. If any of your operations perform a selector on the main thread, your application will freeze at that point.

Brad Larson
Ah, waitUntilAllOperationsAreFinished, of course! For some reason I thought that was just something you call when initialising the queue and not at any point during their execution! Thanks alot :-)
Michael Waterfall
There is a problem with this answer. No matter what you do, your app WILL quit after a short time, even if you block the main thread. applicationWillTerminate is called only as a kindness and the system will not wait long for it to finish before shutting the app down. It may still be a good idea to do anyway, just don't be surprized when not every operation is killed off before the app terminates.
Kendall Helmstetter Gelner
Yes, I assumed that whatever you were doing wouldn't take more than the five seconds the system gives you to quit before it kills your application: http://developer.apple.com/iPhone/library/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/ApplicationEnvironment/ApplicationEnvironment.html#//apple_ref/doc/uid/TP40007072-CH7-SW41
Brad Larson