I'm using background fetch to periodically refresh my app content in background and sometimes it happens that I need more than 30 seconds (the max background fetch permitted time) to complete the update.
My experience is that the app gets killed by iOS watchdog and background fetch gets never called again until I reopen the app in foreground and put it in background again (https://devforums.apple.com/thread/223357, login required). For this reason I added a timer to get notified when the background time is about to end so that I can call the background fetch completion handler and avoid being killed by the watchdog.
My question is: is it acceptable to simply call the completion handler even if the operations the app was carrying on were not completed?
My understanding is that calling the completion handler puts the app in the suspended state and my running threads are frozen and resumed on the next background fetch. Am I allowed to do this or I should terminate all my running threads before calling the completion handler?
Thanks in advance
Related
i noticed that when i hold UIPicker on selection, than all my timers pauses.
I have global timer like clock which is executed every second. However when i hold picker it's pauses all timers in app stops.
Maybe some one had this problem and have a solution ?
Thank you
If your timer should be running regardless of what happens in your UI, you should be running it on a background thread.
Of course, the timer creates its own background process to do the counting. But if you created it on the main thread then maybe the callback selector would be blocked if the UI is blocked, as is the case when holding a UIPickerView.
Just start your timer on a global queue and message the UI on the main queue.
I have a a few threads that needs to run constantly or be locked at my disposal. When I lock the phone or swap applications the thread seems to halt until the application is back in focus.
I have a class Worker that is a sub class of NSThread. There is a method called start which is called by the firstViewController that creates the Worker object.
//method start
[self performSelectorInBackground:#selector(run) withObject:self];
What do I need to do to make my thread run all the time, rather than only running while in focus?
Thanks :)
When your app enters the background, all threads as suspended - unless you've configured your application to use multi-tasking, and your work is being done using the multi-tasking methods. This is detailed at Apple developer.
In short, you basically can't have a thread running constantly in the background on iOS if you want to be accepted in the App store, unless you're a navigation or VOIP application. You can have a thread continue to run for around 10 minutes after you enter the background, but that's it.
I've a task that renders e.g. 50 objects and saves each one as a file. It's set up to continue running in the background and notify the user when the task is completed. While in the foreground, there's a progress bar, that shows the user how far along everything is.
The rendering & writing of files are all done on custom background threads, using GCD. In order to update the progress bar, dispatch_async on the main_queue is called.
Here's my problem...
When the user enters the background, the task continues as planned and, if let alone and still in the background, notifies the user when it's complete. But if the user returns sooner, and the app is still rendering/writing, I/the user would expect to see the progress and all >>> That does not happen. Even though my method to update the progress bar is sent off via dispatch_async on main_queue, the task isn't executed (or the main_queue received if you will), until the 'renter/writing' task I sent in the background is completed and the ExpirationHandler performed.
In the 'applicationWillEnterForeground:' method I tell the app, that it should 'endBackgroundTask:' and set the instance (=self.backgroundTask) to 'UIBackgroundTaskInvalid', but that doesn't make a difference
My question...
Is there a way for me to get back control of a task (running on a GCD-custom background thread) that I sent into the background (beginBackgroundTaskWithExpirationHandler:) when the app closed?
AND/OR
Do I not specifically have to get back control, but do/set something differently?
I have been working on an opencv project for iOS. I was given a simple project to start developing with that captured and displayed frames. I never payed much attention to how it worked until I started having memory issues and traced them back to the original project setup. I now plan to re-write the capturing/displaying code but I don't understand why it worked in the first place. There was a play/pause button which called the method
- (IBAction)play_pause:(id)sender
{
play = !play;
while(play)
{
if (_videoCapture && _videoCapture->grab())
{
(*_videoCapture) >> _display_frame;
//process frame
self.imageView.image = [UIImage imageWithCVMat:_display_frame];
}
}
}
play is just a global bool that signifies whether the application is playing or paused. The strange thing is that the processing should be taking place inside an infinite loop, there is no way out. play is never modified within the loop. In spite of that, when the application is running the play/pause button remains responsive and is capable of flipping the play bool and pausing the execution. Not only that, other bools (use_greyscale for instance) can be flipped by other buttons and their values change inside the loop. I would have expected the application to freeze and never even draw new frames to the screen. The application should stay trapped inside that function for most of its lifetime, unable to perform other tasks such as drawing and UIControl. It seems as though the only way this is possible is if the IBAction call is running on its own thread. I cannot find any evidence of threading in the source code. Could someone explain how apple handles threading in its UI? I was under the impression that there was one main runloop thread and that extra threads were not created automatically. If that is true, how can this behavior be explained?
side note-
What finally made me investigate this was that [UIImage imageWithCVMat:_display_frame] returns an auto-released object. Since all this takes place inside a loop, the objects could not be released without the execution being paused which was causing crashes.
The reason is worked is because the implementation of the cv::VideoCapture::grab() method runs the current run loop to pause the thread until it gets a frame.
When you launch your application, the main function executes a function named UIApplicationMain, which executes CFRunLoopRun. When CFRunLoopRun is executed on the main thread, it runs the main run loop, which is the run loop that processes all the UI events received from the system and refresh the user interface. For information on run loops, you may read Apple Threading Programming Guide.
So, when you execute an infinite loop, your code never returns to the run loop and the waiting events cannot be processed. But in your case, the grab method runs the run loop again with an expiration delay. So the run loop may process incoming events (which may invoke your code again) until the delay expires, then return to your code that will run the run loop again.
If you look at the callstack when you touch the button to pause, you will see this:
main function → run loop → event handling → your code → OpenCV → run loop → event handling → your code
The run loop is running inside itself, which is perfectly fine because run loops are reentrant. Scroll views actually use that behavior: When you scroll a UIScrollView, it runs the run loop again in a different mode in order to ignore some events until you end scrolling.
But I'm not sure the developers of OpenCV had this in mind when they wrote their code. So I think it would be better to load your frames in a background thread/queue.
You are correct, there is no "automatic threading" in iOS. Grand Central Dispatch (GCD) certainly makes threading much easier, but it does not happen automatically.
You can write some debug code and test for [NSThread isMainThread] in the while loop to see if play_pause is indeed being run on the main UI thread, which I suspect it is not.
I am fooling around with NSTimer in a program I am writing and am having some troubles envisioning how I can do a specific task. What I want to have happen is that I want the process I am running (a method responding to a button push) to pause for a period of time and then continue. I can get the basic timer stuff to work by creating the timer in the button push method then watching it fire off and invoking a second method. However, I am not sure how I would go about pausing the button push process that spawned the timer in the first place.
Is there a way to have the button push method wait around until the timer methods fires off and tells the button push method to 'go'? Is there a queue type entry or notification type entry that I can wait on in the button push method that would be sent by the timer selector method?
Any info would be helpful.
I think you want to pause the main thread where your logic is running. Try using
[NSThread sleepForTimeInterval: 1.0]; //pauses the thread for one second