It is a very simple example. I cannot explain why these lines of code cause a crash. I only want to create multiple threads in a for loop.
In the AppDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
for (int i = 0; i < 5; i++) {
[self performSelectorInBackground:#selector(workInBackground)
withObject:nil];
}
return YES;
}
-(void)workInBackground{
}
The app crashes only sometimes (lldb crash, iPhone Simulator 5.0 - 6.1, Xcode Version 4.6.2). I use ARC.
Can anyone explain this behavior?
Update
I "solved" the problem. When I perform a cleanup before each test, the crash no longer occurs.
I don't know what the problem is, but you should check this out:
What are the differences between didFinishLaunchingWithOption and viewDidLoad
Also you could use NSOperationQueue if you have multiple task that you want to run in background.
Ok, so if you read the apple documetation they say: "This method is called after state restoration has occurred but before your app’s window and other UI have been presented. At some point after this method returns, the system calls another of your app delegate’s methods to move the app to the active (foreground) state or the background state." this mean that actually the app in this point in not yet in the foreground state, here you should store somewhere the intention to start your threads, and after that the sistem call the method - (void)applicationDidBecomeActive:(UIApplication *)application, at this point you are absolutelly sure that your app is in a foreground state and active, now if you have recorded the intention to start your threads you can do it, and don't forget to reset the intention variable status
Related
I have a camera app that is running fine on iOS 7. In the viewDidAppear call of my MainViewControllerI am first checking if the application state in not inactive and the application is not in background.
The code sample is given below.
-(void) viewDidAppear
{
if ((UIApplicationStateBackground != [UIApplication sharedApplication].applicationState)
&& (UIApplicationStateInactive != [UIApplication sharedApplication].applicationState))
{
// check if the camera is running
// perform the animation of opening shutter.
}
}
My problem is that on iOS 8 beta 2 [UIApplication sharedApplication].applicationState returns UIApplicationStateInactive hence the check fails. But on iOS 7 [UIApplication sharedApplication].applicationState returns UIApplicationStateActiveand works without any problem.
Has anyone else faced the same issue?
EDIT
A simple experiment of putting breakpoints in viewDidAppear and appDidBecomeActive in xcode 6 reveals that viewdidAppear gets called first. I suppose its a bug in iOS 8
Your view could not possibly appear unless the app was active, or at least becoming active. Views don't do things like appear when the app is inactive or in the background. So I would just delete that condition entirely if I were you. It was never serving any useful function.
(By the way, if you're encountering this situation on launch, what you're experiencing sounds like an issue that I've reported to Apple in another form: in iOS 8, the application doesn't switch to active (so that application:didBecomeActive: fires) until very late, well after the whole interface is up and running. This has caused me to have to rewrite quite a lot of my code. For example, if use my root view controller's viewDidAppear: to register for the applicationDidBecomeActive notification, I then receive that notification shortly afterwards — which is nutty.)
I am currently developing an app that will need to terminate after running in the background for more than five minutes. In order to do this, I will have to have a timer running in the background after the the Home button has been pressed or in case of an interruptions such as an SMS or a telephone call, then, after five minutes the applicationWillTerminate method will be called. My first question is should I put the applicationWillTerminate in the applicationWillResignActive method or in the applicationDidEnterBackground method? My second question is since this is an app with more that one view, Should I write these things in the AppDelegate class or elsewhere? Thank you for your response.
1) You can't force your app to finish programatically.
2) You should never call these AppDelegate methods by yourself. They're meant to be called only by the system.
Reference: UIApplicationDelegate Protocol Reference.
This is pretty ghetto, but what you can do is make your app crash when you want it to exit, and it will close automatically, granted that's not closing the app, but there's no real harm in it as long as you are in control of how it crashes try to go for a bad access error, aka trying to access something that has been deallocated
as for running a timer in the background, i don't know per say if you can do that, but as an alternative you can save the time when they leave the app aka the app goes into the background and then you can have all the events return to your app of the view controller that is first responder, and each UIEvent has a time stamp, and regardless of which event it is you can compare the time stamps and see if it's greater than 5 minutes
Regardless i don't suggest any of the above, but that is the best answer i can come up with for your question
the code for receiving events out side of your app
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
will start the event tracking and the call back is:
- (void)remoteControlReceivedWithEvent:(UIEvent *)event { }
but you have to remember to
[self becomeFirstResponder];
this tells the device which view controller to go to for the event tracking, oh and don't forget to resign first responder, and endReceivingRemotecontrolEvents
Question 1.
I am seeing following behavior on iphone 4 and iOS 5.0.1
register using addPeriodicTimeObserverForInterval to receive updates every 250 ms and update UI.
works well till the app goes to background. For eg. hit the home button or lock the screen,
When app comes back to foreground the player starts playback again but the updates dont fire again. If user hits the play pause button again on the UI updates start firing again.
This can be seen in the demo app from apple as well.
Question 2
Can we not mix C based Audio Session APIs with AV foundation classes? For eg. I have my C based listener registered when AudioInterruptions. But when I use AVPlayer with kAudioSessionCategory_PlayAndRecord they dont get called. When app goes to background AVPlayer pauses without the C based listener getting called.
Is this expected or can I do something? Please note that once I have disposed the AVPlayer instance and my app goes to background again wiht kAudioSessionCategory_PlayAndRecord
set as category the listener function gets invoked.
For your first problem, most likely you are not releasing the addPeriodicTimeObserverForInterval as suggested. Try putting something like this in your AppDelegate:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[_audioManager.audioPlayer removeTimeObserver:_audioManager.timeObserver];
_audioManager.isUIActive = NO;
}
and the appropriate method to restart the periodic time observer:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[_audioManager setUpTransportUI];
_audioManager.isUIActive = YES;
}
where setUpTransportUI recreates your time observer.
I tried to simulate memory warning on iOS Simulator and it turned out that when the app was in the background, the function didn't get called at that moment, but after the app became active again that the applicationDidReceiveMemoryWarning was being called.
When tested with Instrument:Activity Monitor, my app didn't release any memory when in the background while the other apps memory consumption were getting less.
However, if I call applicationDidReceiveMemoryWarning via applicationDidEnterBackground, the memory get released correctly, but I don't want to release memory at this stage though.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[glView applicationDidEnterBackground:application];
// Function works if it's called from here, but not what I want.
[self applicationDidReceiveMemoryWarning:application];
}
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
[glView applicationDidReceiveMemoryWarning:application];
}
How do I fix this?
Unfortunately, what you want to do is discouraged by Apple in the iOS App Programming Guide. An app briefly enters the background, allowing you to free up memory. After that, the app is suspended and cannot receive messages, except applicationWillTerminate. If a low-memory warning fires, the operating system kills suspended apps as needed.
Which is the proper delegate to implement when an application is waking up from being in the background and you want it to prep it to be active?
applicationWillEnterForeground vs applicationDidBecomeActive -- What's the difference?
Which is the proper delegate to implement for when an application is going to sleep and you want to prep it to cleanup and save data?
applicationWillResignActive vs. applicationDidEnterBackground -- What's the difference?
Also, I've noticed that applicationWillResignActive gets called when an incoming SMS or call comes in but the user chooses to click Ok and continue. I don't want my app to take any action in these cases. I just want it to keep running without any intermediate cleanup since the user didn't exit the app. So, I would think it makes more sense to do cleanup work just in applicationDidEnterBackground.
I would appreciate your input on best practices to follow on choosing which delegates to implement for waking up and going to sleep as well as considering events like being interrupted by SMS/calls.
Thanks
When waking up i.e. relaunching an app (either through springboard, app switching or URL) applicationWillEnterForeground: is called. It is only executed once when the app becomes ready for use, after being put into the background, while applicationDidBecomeActive: may be called multiple times after launch. This makes applicationWillEnterForeground: ideal for setup that needs to occur just once after relaunch.
applicationWillEnterForeground: is called:
when app is relaunched
before applicationDidBecomeActive:
applicationDidBecomeActive: is called:
when app is first launched after application:didFinishLaunchingWithOptions:
after applicationWillEnterForeground: if there's no URL to handle.
after application:handleOpenURL: is called.
after applicationWillResignActive: if user ignores interruption like a phone call or SMS.
applicationWillResignActive: is called:
when there is an interruption like a phone call.
if user takes call applicationDidEnterBackground: is called.
if user ignores call applicationDidBecomeActive: is called.
when the home button is pressed or user switches apps.
docs say you should
pause ongoing tasks
disable timers
pause a game
reduce OpenGL frame rates
applicationDidEnterBackground: is called:
after applicationWillResignActive:
docs say you should:
release shared resources
save user data
invalidate timers
save app state so you can restore it if app is terminated.
disable UI updates
you have 5 seconds to do what you need to and return the method
if you don't return within ~5 seconds the app is terminated.
you can ask for more time with beginBackgroundTaskWithExpirationHandler:
The official documentation.
Managing Your App's Life Cycle is helpful to your questions. For quick concept, you can see Figures in that document.
You can also read the comment from the code generated by the XCode Wizard. Listed as follows:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
/*
Sent when the application is about to move from active to inactive state.
This can occur for certain types of temporary interruptions (such as an
incoming phone call or SMS message) or when the user quits the application
and it begins the transition to the background state.
Use this method to pause ongoing tasks, disable timers, and throttle down
OpenGL ES frame rates. Games should use this method to pause the game.
*/
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
/*
Use this method to release shared resources, save user data, invalidate
timers, and store enough application state information to restore your
application to its current state in case it is terminated later.
If your application supports background execution, this method is called
instead of applicationWillTerminate: when the user quits.
*/
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
/*
Called as part of the transition from the background to the active state;
here you can undo many of the changes made on entering the background.
*/
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
/*
Restart any tasks that were paused (or not yet started) while the
application was inactive. If the application was previously in the
background, optionally refresh the user interface.
*/
}
- (void)applicationWillTerminate:(UIApplication *)application
{
/*
Called when the application is about to terminate.
Save data if appropriate.
See also applicationDidEnterBackground:.
*/
}
For more detailed explanations, please refer to official document for UIApplicationDelegate
I was still a bit confused with Dano's answer so I did a little test to get the flow of events in certain scenarios for my reference, but it might be useful to you too. This is for apps that DO NOT use UIApplicationExitsOnSuspend in their info.plist. This was conducted on an iOS 8 simulator + confirmed with iOS 7 device. Please excuse Xamarin's event handler names. They are very similar.
Initial and all subsequent launches from a not-running state:
FinishedLaunching
OnActivated
Interruption (phone call, top slide-down, bottom slide-up):
Home button double-press listing inactive apps, then reselecting our app:
OnResignActivation
OnActivated
Home button double-press listing inactive apps, selecting another app, then relaunching our app:
Home button single press, then relaunch:
Lock (on/off button), then unlock:
OnResignActivation
DidEnterBackground
WillEnterForeground
OnActivated
Home button double-press, and terminate our app: (subsequent relaunch is first case)
OnResignActivation
DidEnterBackground
DidEnterBackground (iOS 7 only?)
Yes, DidEnterBackground is called twice on iOS7 device. Both times UIApplication state is Background. However, iOS 8 simulator does not. This needs testing on iOS 8 device. I will update my answer when I get my hand on it, or someone else could confirm.
applicationWillEnterForeground is called:
when app is relaunched(comes from background to foreground)
This method is not invoked when app starts for the first time i.e when applicationDidFinishLaunch is called but only when comes from background
applicationDidBecomeActive
applicationDidBecomeActive is called
when app is first launched after didFinishLaunching
after applicationWillEnterForeground if there’s no URL to handle.
after application:handleOpenURL: is called.
after applicationWillResignActive if user ignores interruption like a phone call or SMS.
after disappearing of alertView anywhere from the application
applicationWillResignActive is called when system is asking for permissions. (in iOS 10). Just in case someone hit into the same trouble as me...
In iOS 8+ there is a subtle but important difference for taking phone call.
In iOS 7 if user takes phone call both applicationWillResignActive: and applicationDidEnterBackground: are called. But in iOS 8+ only applicationWillResignActive: is called.
For iOS 13+ the following methods will be executed:
- (void)sceneWillEnterForeground:(UIScene *)scene
- (void)sceneDidBecomeActive:(UIScene *)scene