I want execute a function all time while my ios App is running.
What is the class where I need write this function, in the delegate?
I'm confused because if I declared this in viewContorller and change to other viewController this break. Or there is a function like
func locationManager(manager:CLLocationManager, didUpdateLocations locations:[AnyObject]) {
that this is running all time?
Thanks!
If you are referring specifically to didUpdateLocations, this is a method that you don't call directly, but rather the OS calls to deliver location updates to you any time it receives them. While it's typically recommended that your location code is handled by some singleton somewhere to consolidate/encapsulate all the location logic, if you create a CLLocationManager and tell it to startUpdatingLocations, that method will be called constantly** by the OS without you having to deal with timers, loops etc.
** When the app is backgrounded the location updates will stop, and when the app comes back to the foreground the location updates will resume without you needing to restart them. These can come as often as once per second, but once again relies on the OS determining the location of the devices and delivering those updates to you.
If you're referring to anything else that is a different answer, but I suspect you're referring directly to location updates.
I suggest to put the function in another file, and use an NSThread
- (void)createThread
{
[NSThread detachNewThreadSelector:#selector(startBackgroundJob) toTarget:self withObject:nil];
}
- (void)startBackgroundJob
{
[self performSelectorOnMainThread:#selector(monitorApp) withObject:nil waitUntilDone:NO];
}
- (void)monitorApp
{
}
Related
I am working on an iOS application that, say on a button click, launches several threads, each executing a piece of Open GL code. These threads either have a different EAGLContext set on them, or if they use same EAGLContext, then they are synchronised (i.e. 2 threads don't set same EAGLContext in parallel).
Now suppose the app goes into background. As per Apple's documentation, we should stop all the OpenGL calls in applicationWillResignActive: callback so that by the time applicationDidEnterBackground: is called, no further GL calls are made.
I am using dispatch_queues to create background threads. For e.g.:
__block Byte* renderedData; // some memory already allocated
dispatch_sync(glProcessingQueue, ^{
[EAGLContext setCurrentContext:_eaglContext];
glViewPort(...)
glBindFramebuffer(...)
glClear(...)
glDrawArrays(...)
glReadPixels(...) // read in renderedData
}
use renderedData for something else
My question is - how to handle applicationWillResignActive: so that any such background GL calls can be not just stopped, but also be able to resume on applicationDidBecomeActive:? Should I wait for currently running blocks to finish before returning from applicationWillResignActive:? Or should I just suspend glProcessingQueue and return?
I have also read that similar is the case when app is interrupted in other ways, like displaying an alert, a phone call, etc.
I can have multiple such threads at any point of time, invoked by possibly multiple ViewControllers, so I am looking for some scalable solution or design pattern.
The way I see it you need to either pause a thread or kill it.
If you kill it you need to ensure all resources are released which means again calling openGL most likely. In this case it might actually be better to simply wait for the block to finish execution. This means the block must not take too long to finish which is impossible to guarantee and since you have multiple contexts and threads this may realistically present an issue.
So pausing seems better. I am not sure if there is a direct API to pause a thread but you can make it wait. Maybe a s system similar to this one can help.
The linked example seems to handle exactly what you would want; it already checks the current thread and locks that one. I guess you could pack that into some tool as a static method or a C function and wherever you are confident you can pause the thread you would simply do something like:
dispatch_sync(glProcessingQueue, ^{
[EAGLContext setCurrentContext:_eaglContext];
[ThreadManager pauseCurrentThreadIfNeeded];
glViewPort(...)
glBindFramebuffer(...)
[ThreadManager pauseCurrentThreadIfNeeded];
glClear(...)
glDrawArrays(...)
glReadPixels(...) // read in renderedData
[ThreadManager pauseCurrentThreadIfNeeded];
}
You might still have an issue with main thread if it is used. You might want to skip pause on that one otherwise your system may simply never wake up again (not sure though, try it).
So now you are look at interface of your ThreadManager to be something like:
+ (void)pause {
__threadsPaused = YES;
}
+ (void)resume {
__threadsPaused = NO;
}
+ (void)pauseCurrentThreadIfNeeded {
if(__threadsPaused) {
// TODO: insert code for locking until __threadsPaused becomes false
}
}
Let us know what you find out.
i am new to iOS development
I want to do some task if user exits application from homescreen
Is there any way in which we can determine ?
Please help, and thanks in advance !!
When you enter didEnterBackground, you need to check the last visible controller that was on the navigation stack. If it is Home Screen, do what you want to do there.
- (void)applicationDidEnterBackground:(UIApplication *)application {
id controller = self.navigationController.visibleViewController;
if ([controller isKindOfClass:[HomeViewController class]])
{
//do your stuff here
}
}
This function:
func applicationWillTerminate(application: UIApplication) {}
is called when your application is about to terminate.
From the Apple docs:
This method lets your app know that it is about to be terminated and
purged from memory entirely. You should use this method to perform any
final clean-up tasks for your app, such as freeing shared resources,
saving user data, and invalidating timers. Your implementation of this
method has approximately five seconds to perform any tasks and return.
If the method does not return before time expires, the system may kill
the process altogether.
For more info take a look at: https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/index.html
So, i need to start a timer in the app delegate method applicationDidEnterBackground:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
globalBackgroundTimer = [NSTimer timerWithTimeInterval:30 invocation:nil repeats:NO];
}
the timer is declared like so in app delegate.h:
extern NSTimer * globalBackgroundTimer;
While the timer runs, i receive background location updates (is enabled in plist), in a view controller, and i want to check constantly in locationManager:didUpdateLocations:
For when the timer has expired so i can end the location updates.
... //code omitted
//this is called repeatedly when the app is in the background, and checks whether the global variable is instantiated, and if it has expired.
if(globalBackgroundTimer)
{
NSLog(#"timer alive");
if(!globalBackgroundTimer.isValid)
{
[locationManager stopUpdatingLocation];
NSLog(#"background timer invalid, stopping location updates");
}
}
But i can't make it work (Mach-O-linker error),
however i also read that this approach was ill-advised. So what do you guys suggest?
Figure out a mechanism to store the state of the timer when the app enters the background (NSUserDefaults or Documents sandbox). Then, when the app enters foreground, recalculate the difference using the NSDate information you saved.
(I realize this may already have been what you were doing before you posted this question.)
One question and one issue:
I have the following code:
- (void) registerForLocalCalendarChanges
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(localCalendarStoreChanged) name:EKEventStoreChangedNotification object:store ];
}
- (void) localCalendarStoreChanged
{
// This gets call when an event in store changes
// you have to go through the calendar to look for changes
[self getCalendarEvents];
}
These methods are in a class/object called CalendarEventReporter which contains the method getCalendarEvents (in the callback).
Two things:
1) If the app is in the background the callback does not run. Is there a way to make it do that?
2) When I bring the app back into the foreground (after having changed the calendar on the device) the app crashes without any error message in the debug window or on the device. My guess is that the CalendarEventReporter object that contains the callback is being garbage-collected. Is that possible? Any other thoughts on what might be causing the crash? Or how to see any error messages?
1) In order for the app to run in the background you should be using one of the modes mentioned in the "Background Execution and Multitasking section here:
uses location services
records or plays audio
provides VOIP
services
background refresh
connection to external devices
like through BLE
If you are not using any of the above, it is not possible to get asynchronous events in the background.
2) In order to see the crash logs/call stack place an exception breakpoint or look into the "Device Logs" section here: Window->Organizer->Devices->"Device Name" on left->Device Logs on Xcode.
To answer your first question, take a look at https://developer.apple.com/library/ios/documentation/iphone/conceptual/iphoneosprogrammingguide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html
What I did to get code running in the background is to do something like
In the .h file
UIBackgroundTaskIdentifier backgroundUploadTask;
In the .m file
-(void) functionYouWantToRunInTheBackground
{
self.backgroundUploadTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[self endBackgroundUpdateTask];
}];
//code to do something
}
-(void) endBackgroundUpdateTask
{
[[UIApplication sharedApplication] endBackgroundTask: self.backgroundUploadTask];
self.backgroundUploadTask = UIBackgroundTaskInvalid;
}
The code above I pretty much learned from objective c - Proper use of beginBackgroundTaskWithExpirationHandler
As for your second question, you should set a breakpoint where code is supposed to run when you bring the app back to the foreground. No one can figure out why an app crashes if not given enough code or information.
The solution to the second part of the question was to raise the scope of the object containing the callback code. I raised it to the level of the containing ViewController. This seems to work. I still can't figure out how to raise the Notification (i.e. execute the call back) if the notification comes while the app is in the background/suspended. This prevented the object containing the callback from being cleaned up.
For example:
- (void)someFunc {
[self someFunc1];
[self someFunc2];
[self someFunc3];
}
I call someFunc. As I understand if I interrupt the application then the application doesn't guarantee that all the inner code in someFunc will be performed.
I must call someFunc1, someFunc2 and someFunc3 only once.
The problems I don't know how to solve:
someFunc1, someFunc2 and someFunc3 should be called atomically.
storing info for next launch. For example if we successfully have performed someFunc1 only then at next launch the application should call someFunc2 and someFunc3 only.
I know about method applicationWillTerminate:, but I don't know how to solve the current issue with it.
EDITED
Multitasking is not a solution because Even if the device is running iOS 4 or later, the device may not support multitasking., so it doesn't solve the general problem and makes the final solution more difficult only.
EDITED
For those who spam with off topic answers: read the title first - Save state when user exits an application. Where have you seen here putting the application into background?
This does't make sense. If these functions are running on the main thread, there is no way that the application can terminate normally while your functions are running. This is because the events sent like applicationWillTerminate: are sent on the same thread.
If your function is running on a different thread to the main thread, you will need to save some state information after each function completes, but you still have a race condition.
It might be better to check your application's state before running each function. For example, if you have a three step login/registration process with a server, you should query the server to see if the stage has been completed already before running it.
It's difficult to be more specific without knowing what you are doing in these functions.
You should use background tasks !
Take a look at the documentation here :
Executing a Finite-Length Task in the Background
Put the call of someFunc in the middle of the background task.
If your app goes to the background state, you'll have extra time to finish the execution of the method.
Make your functions to return bool, and when you call them, store the bool value to nsdefaults.
When the app restarts,check the bools from sndefaults, and if they are NO, run the functions and update them.
Nobody wants to help. So my temporary solution:
to save a last state I use a writing to a file because it enables to set its operation as atomic/nonatomic
I have replaced this code with something like this:
typedef enum {
state1,
state2,
state3
} MyState;
#property (assign) MyState state;
-(void)someFunc {
switch (state) {
case state1:
{
[self someFunc1];
state = state2;
[self someFunc];
break;
}
case state2:
{
[self someFunc2];
state = state3;
[self someFunc];
break;
}
default:
break;
}
}