I want to send a timestamp to a remote server, and wait for the callback of success, then store the timestamp locally, if remote server did not respond.
Is it something that I could put into applicationDidEnterBackground implementation?
According to iOS Developer Library UIApplicationDelegate Protocol Reference
Your implementation of this method has approximately five seconds to
perform any tasks and return. If you need additional time to perform
any final tasks, you can request additional execution time from the
system by calling beginBackgroundTaskWithExpirationHandler:. In
practice, you should return from applicationDidEnterBackground: as
quickly as possible. If the method does not return before time runs
out your app is terminated and purged from memory.
You should perform any tasks relating to adjusting your user interface
before this method exits but other tasks (such as saving state) should
be moved to a concurrent dispatch queue or secondary thread as needed.
Because it's likely any background tasks you start in
applicationDidEnterBackground: will not run until after that method
exits, you should request additional background execution time before
starting those tasks. In other words, first call
beginBackgroundTaskWithExpirationHandler: and then run the task on a
dispatch queue or secondary thread.
So you have approximately 5 seconds to perform any tasks and return in "applicationDidEnterBackground" methods.
If you want to do any network stuff before going to the background, you should ask for extra time with beginBackgroundTaskWithExpirationHandler:.
You can do that in dispatch_async and you can wait the server answer and do something with your data, but you can't stop the enter background...
try this code
dispatch_queue_t savingQueue = dispatch_queue_create("savingQue", NULL);
dispatch_async(savingQueue, ^{
//do something in bg....
dispatch_async(dispatch_get_main_queue(), ^{
});
});
dispatch_release(savingQueue);
Related
What does it mean that input sources such as port deliver events to a run loop async while timers deliver events synchronously.
Does the timer block the thread?
The Threading Programming Guide: Run Loops says:
A run loop receives events from two different types of sources. Input sources deliver asynchronous events, usually messages from another thread or from a different application. Timer sources deliver synchronous events, occurring at a scheduled time or repeating interval. Both types of source use an application-specific handler routine to process the event when it arrives.
But a timer only blocks the thread while the timer’s closure or selector method is running. But as soon as you return from that, the thread is no longer blocked. So make sure to get in and out as quickly as possible.
For example, if you have scheduled a timer to fire in 10 seconds, and the code in the timer’s handling closure/selector takes 100 msec to run, then the thread is not blocked until the timer fires, and then only for 100 msec. Same with repeating timers.
Bottom line, as long as you’re not doing anything too computationally expensive in your timer handler, there’s nothing to worry about. And if you do need to do anything that might block for any material amount of time, then either have your timer handler asynchronously dispatch that relevant code to some background queue, or just schedule a GCD timer to run on a background queue directly, bypassing Timer altogether.
But for most Timer use-cases, this just isn’t an issue.
I have a method in my AppDelegate that saves a NSManagedObjectContext passed as a parameter. This method may be called on either the main thread or a background thread, and I want to ensure that when this method is called the main thread doesn't kill it halfway through when the user terminates the program or what have you. How do I prevent the main thread from killing this thread when this method is being executed?
I also want to do this for writing data to a plist file -- this also may happen outside of the main thread.
I am doing all my background work by way of GCD and dispatch_async
Brad Larson had some suggestions on this post that should help you.
In your appDelegate, when your app is getting pushed to the background, it calls applicationDidEnterBackground. From this routine, you can see if your method is currently in progress, and can behave accordingly.
Depending on how long your task takes to run there are two options:
If it will take significantly less than 5 seconds, you can just have your applicationDidEnterBackground wait until your task is completed before releasing. If you take longer than 5 seconds, your app will just get force-killed.
If it could be a while, you can try beginBackgroundTaskWithExpirationHandler: to start a background task that finishes off your task.
I am trying to re-schedule queued block that will handle the update operations.
Main goal is updating UI objects (online user table...) with minimum amount of (UI update request). (Server sometimes rain down massive amount of updates, yay!)
For simplicity main scenario is;
The dispatch_queue_t instance (queue that will handle given UI updating block) is a serial dispatch queue (private dispatch queue)
The operation (UI updating block) is scheduled with dispatch_after with t amount of time (Instead of updating for each data set update, collect update requests within t amount of time and perform a single UI update for them)
In case our data set updated, check if there already exist a scheduled event. If yes, unschedule it from dispatch_queue_t instance. Then re-schedule same block with t amount of time delay.
Also;
t is a small amount of time interval that possibly won't be noticed by the user (like 500 ms.)
Any alternative approach is welcome.
My motive behind this;
i applied same logic via Android's Handler (post & removeCallbacks combination with Runnable instance) and i hope i could achieve the same on iOS.
Edit:
As #Sven suggested usage of NSOperationQueue is more suitable for the scenario as they support cancelling each NSOperation. I skimmed through documents and found;
Canceling Operations
Once added to an operation queue, an operation object is effectively owned by the queue and cannot be removed. The only way to dequeue an operation is to cancel it. You can cancel a single individual operation object by calling its cancel method or you can cancel all of the operation objects in a queue by calling the cancelAllOperations method of the queue object.
You should cancel operations only when you are sure you no longer need them. Issuing a cancel command puts the operation object into the “canceled” state, which prevents it from ever being run. Because a canceled operation is still considered to be “finished”, objects that are dependent on it receive the appropriate KVO notifications to clear that dependency. Thus, it is more common to cancel all queued operations in response to some significant event, like the application quitting or the user specifically requesting the cancellation, rather than cancel operations selectively.
This can easily be done with GCD as well, no need to reach for the big hammer that is NSOperationQueue here.
Just use a non-repeating dispatch timer source directly instead of dispatch_after (which is just a convenience wrapper around such a timer source, it doesn't actually enqueue the block onto the queue until the timer goes off).
You can reschedule a pending timer source execution with dispatch_source_set_timer().
You cannot remove or otherwise change an operation enqueued on a dispatch queue. Try using the higher level NSOperationQueue instead which supports cancellation.
I need to upload some left-over data to server in application:didFinishLaunchingWithOptions, but it takes some time and eventually the app may be killed as it cannot finish launching in time, so I used:
[myObject performSelector:withObject:afterDelay:]
with 0.2f delay, to let application:didFinishLaunchingWithOptions finish, but it does not look like a good idea, so I wonder is there a way I can perform the selector just after application:didFinishLaunchingWithOptions?
I know there are applicationDidBecomeActive but I need it to be executed in application:didFinishLaunchingWithOptions.
If you use a delay of 0, it will be executed as soon as control returns to the runloop.
However, if this is blocking for too long in appDidFinishLaunching, then it will also block no matter when you run it. You really should move this code to a background thread. Synchronous network access on the main thread is never a good idea.
I launch a method that is, essentially, an endless loop using dispatch_queue_create and then dispatch_async (and then the code-loop is inside the dispatched block).
The loop runs perfectly. However, when the application gets backgrounded, it pauses. Then it restarts when the app takes the foreground.
How can I prevent this from happening? I've been looking here but it seems that the priority is not one of the things I can choose.
Use the -[UIApplication beginBackgroundTaskWithExpirationHandler:] method to start a background task. The OS will give you ten minutes and call the expirationHandler block when it ends.
This method will return UIBackgroundTaskInvalid if the device can't run code in background or the task id that you must use to end it otherwise.
You can (and should) end it sooner by calling -[UIApplication endBackgroundTask];
You can probably start a task in the beginning of your block and end it when it ends, if it is a endless loop just start a task in the applicationWillResignActive method and end it on applicationDidBecomeActive. But remember, you only have ten minutes, to have more time your app would have to use location, audio, or voip.