I have an animating sine wave in my app that needs to be reset when the user hits the home button or locks their phone (turning off the screen). Once the user brings the app back to the foreground, the sine wave animation is triggered again. This works fine until I realized it was occurring when the microphone access permission pops up. So the microphone access pops up, causing my app to go into the background and the animation to turn off, but the app is still visible. Any way I can know that the mic access pop up is occurring, so I can make some kind of if statement?
-(void) appDidEnterForeground:(NSNotification *)notification
{
if( viewIsUp == NO)
{
[self.sineWave.layer removeAllAnimations];
}
else
{
[self.sineWave animateWave];
}
}
-(void) appDidEnterBackground:(NSNotification *)notification
{
if(viewIsUp)
{
[self.sineWave.layer removeAllAnimations];
}
}
I accidentally set UIApplicationWillResignActiveNotification as the notification to call appDidEnterBackground. When the microphone access pop up would display, the only notification that would get called was UIApplicationWillResignActiveNotification. So when the home button was tapped or the screen was locked, I would remove the animation when UIApplicationDidEnterBackgroundNotification was called and when the mic access pop up displayed, I would leave the animation as it is when UIApplicationWillResignActiveNotification gets called. Worked out nicely. Hope this helps someone.
Related
My UI uses animation of a UILabel to indicate a particular state. I turn that state on and off by using a key in NSUserDefaults standardUserDefaults. The animation restarts correctly (in the simulator) when the app becomes active after simulating the Home button and then clicking on the app. But it doesn't restart correctly if I simulate the Lock button and then click Home. Both events show in the console and the method -(void)startFlashingButton is called in both cases. I can't figure out why it works in one case and not in the other. I would appreciate any help.
Edit 2/14/17: I read several posts on other boards relating to UINotification. It is apparently very difficult to get to work. My animation gets triggered when a notification comes in to the app delegate. I wanted to set up a kind of "do not disturb" system that would silence notifications at a particular time. My understanding is that this cannot be automated by UINotification because the app does not see a notification unless it is front and center OR it is in the background and the user taps on one of the action buttons. If the app is in background and the user ignores the alert, the app will not get triggered and thus has no way of knowing if the do not disturb time has been reached. Also, you can't do this reliably with an NSTimer because the timer won't be recognized when the app is suspended, which it would be shortly after going to background. So, to put it briefly, I have a much bigger problem than the simulation not running. But thanks to all of you for your replies.
Here is the startFlashingButton method:
-(void) startFlashingButton
{
NSUserDefaults *storage = [NSUserDefaults standardUserDefaults];
if([storage boolForKey:#"animation started"] == YES){
// Fade out the view right away
[UIView animateWithDuration:2.0
delay: 0.0
options: (UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionRepeat | UIViewAnimationOptionAllowUserInteraction)
animations:^{
self.timerLabel.alpha = 0.0;
}
completion:^(BOOL finished){
// Wait one second and then fade in the view
[UIView animateWithDuration:1.0
delay: 2.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
self.timerLabel.alpha = 1.0;
}
completion:nil];
}];
}
[storage synchronize];
}
In -viewDidLoad, I set up the app to be notified when it becomes active as follows:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(startFlashingButton) name:UIApplicationDidBecomeActiveNotification object:nil];
In the app delegate, I synchonize the user defaults when the app enters background as follows:
- (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.
NSLog(#"application did enter background");
NSUserDefaults *storage = [NSUserDefaults standardUserDefaults];
[storage synchronize];
As Apple's documentation on background transition cycle states
When the user presses the Home button, presses the Sleep/Wake button, or the system launches another app, the foreground app transitions to the inactive state and then to the background state. These transitions result in calls to the app delegate’s applicationWillResignActive: and applicationDidEnterBackground: methods.
Hence The app might resign being active but not being in the background when you lock and then press the home button.
Try creating this helper method and call it in both applicationWillResignActive: and applicationDidEnterBackground:
-(void)saveUserDefaults {
NSLog(#"application did enter background");
NSUserDefaults *storage = [NSUserDefaults standardUserDefaults];
[storage synchronize];
}
Also, make sure that Application does not run in background in your info.plist is set to NO else your app will go to the suspended.
I am trying to change the screen shot that is automatically captured by iOS when the app enters the background.
However I am not entirely sure exactly when this screenshot is taken.
For example:
If you pull down the notification bar while in the app the following method is called:
- (void) applicationWillResignActive:(UIApplication *) application {
}
Also if you double tap the home button while in the app the same method is called. In addition if an alert view is show 'applicationWillResignActive' is called.
But in both of these cases
- (void) applicationDidEnterBackground:(UIApplication *) application {
}
is not called.
So my question is, is there a screenshot captured after the call to applicationWillResignActive even if the application does not enter the background? Or does iOS only capture a screenshot after applicationDidEnterBackground?
Look at official doc - "Preventing Sensitive Information From Appearing In The Task Switcher".
It says applicationDidEnterBackground: should be used for the said purpose.
you can look over here, in summary, change the view before return from applicationDidEnterBackground:
Yes.
- (void) applicationWillResignActive:(UIApplication *) application {
}
is called when you pull down the notification bar or even when you double click the home button. You have to do something here to prevent your sensitive information to be captured by the OS. One workaround might be:
Set a blurry screen overlay before the app goes in the background
Once the app becomes active remove this overlay
Something like this:
-(void)applicationWillResignActive:(UIApplication *)application
{
imageView = [[UIImageView alloc]initWithFrame:[self.window frame]];
[imageView setImage:[UIImage imageNamed:#"blurryImage.png"]];
[self.window addSubview:imageView];
}
And then remove this overlay before the application enters foreground:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
if(imageView != nil) {
[imageView removeFromSuperview];
imageView = nil;
}
}
is called when you pull down the notification bar or even when you double click the home button. You have to do something here to prevent your sensitive information to be captured by the OS. One workaround might be:
Set a blurry screen overlay before the app goes in the background
Once the app becomes active remove this overlay
I am currently making an iOS game using sprite kit. In one of my SKScenes, my store scene, the user can watch an AdColony ad. The ad plays fine, but after it is finished, the store scene is deallocated and the app returns to the menu screen. Why is this happening, and how can I return to the store scene without deallocating it?
Edit: Here's my code
//User taps a button (really a skspritenode)
//UIAlertView pops up asking them to watch a video
alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
//User tapped button 1 (aka agreed to watch video)
if (buttonIndex == 1){
//Present video
[AdColony playVideoAdForZone:#"xxxxxxxxxxxxxxxxxxxx" withDelegate:self];
}];
}
I’m getting multiple UIKeyboardDidShowNotification and UIKeyboardDidHideNotification notifications when I rotate the device and I can’t figure out why.
I have an app that lets you edit the text for each picture. (It’s in a UITextView.) Most of the time I need to slide the text up so you can see it above the keyboard, then I slide it down when you are done editing. Then I do a database update to save the new text. I use notifications to tell me when the keyboard is displayed and when it goes away. It works fine on iPad when the user taps the keyboard close icon on the keyboard. It also works fine if the user swipes to the next page and iOS closes the keyboard. Since iPhones and iPods don’t have a keyboard close key, I wrote a method to close the keyboard when the picture or background is tapped. It works fine there too. However, when I rotate the device, I get multiple hide and show notifications. And I don’t know why.
Instead of getting one UIKeyboardDidHideNotification notification, I get a hide, a show, a hide, and then a show.
2:39:44.200 Picts for SLPs[16533:907] keyboardDidHide called. Keyboard showing flag is YES.
2:39:51.751 Picts for SLPs[16533:907] keyboardDidShow called. Keyboard showing flag is NO.
2:39:55.224 Picts for SLPs[16533:907] keyboardDidHide called. Keyboard showing flag is YES.
2:39:56.124 Picts for SLPs[16533:907] keyboardDidShow called. Keyboard showing flag is NO.
I posted the relevant code below. It is taken mostly from StackOverflow posts (Thanks guys).
In my class that displays the pictures I start notifications when it is initialized.
- (id)initWithParentView:(UIView *)parentview {
self = [super init];
if (self) {
_parentView = parentview;
if (ALLOW_DATABASE_EDITING) [self startNotifications];
}
return self;
}
- (void)startNotifications {
// Listen for keyboard appearances and disappearances
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardDidShow:)
name:UIKeyboardDidShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardDidHide:)
name:UIKeyboardDidHideNotification
object:nil];
}
The View Controller calls the hideKeyboard method in the View when the user taps on the picture.
- (void)dismissKeyboard {
if (self.showArtic.keyBoardIsShowing) {
[self.showArtic hideTheKeyboard];
}
}
resignFirstResponder sends a notification that closes the keyboard
- (void)hideTheKeyboard {
id <ShowArticDelegate> SA_delegate = _delegate;
// Don't update the database when there is no text.
if ( ![self.editableTextView.text isEqualToString:#""] ) {
[SA_delegate updateTextInDatabase:self.editableTextView.text];
}
[self.editableTextView resignFirstResponder];
}
These methods respond to the notifications.
- (void)keyboardDidHide:(NSNotification *)notification {
NSLog(#"keyboardDidHide called. Keyboard showing flag is %#.", self.keyBoardIsShowing ? #"YES" : #"NO");
self.keyBoardIsShowing = NO;
// Move the text, update the database
}
- (void)keyboardDidShow:(NSNotification *)notification {
NSLog(#"keyboardDidShow called. Keyboard showing flag is %#.", self.keyBoardIsShowing ? #"YES" : #"NO");
self.keyBoardIsShowing = YES;
// Move the text
}
any chance you could manually dismiss the keyboard and clean up your database from within this method:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
and then if you want the keyboard brought back up once the rotation completes, manually call your method to display it from within:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
That may or may not fit your needs, but it's a pretty common and clean technique to "get out of the way" while Apple handles the rotation, and then get back to business once everything is back on solid ground again.
I am working on Notification and my understanding on this is that IOS notifications like "textFieldShouldBeginEditing:(UITextField *)iTextField" gets posted only when you tap on a text field.
To my strange notice, my code is receiving this notification when I am tapping on "Back" button to go back to my previous view.
What are the possible chances of me getting this notification again. I believe we need not to register for such notifications. I have registered only for keyboard hide/show notifications.
Please suggest.
I found the issue. The issue was I was adding my textfield as first responder before server call and then was only removing it when you hit the return button or hit any other text field. That's why it was not getting resigned when back button was pressed. Now I have resigned it soon after server call.
Edit: I misunderstood the question. See the OP's answer.
Well, the keyboard will disappear upon navigation. It makes sense that the notification is posted in this case. One way to ignore notifications generated in response to view transitions is to keep track of your view controller's state.
- (void)viewWillDisappear:(BOOL)animated {
_transitioningView = YES;
}
- (void)viewDidDisappear:(BOOL)animated {
_transitioningView = NO;
}
- (void)viewWillAppear:(BOOL)animated {
_transitioningView = YES;
}
- (void)viewDidAppear:(BOOL)animated {
_transitioningView = NO;
}
Now, in the selector called by your keyboard notification, you can just return if the view is transitioning.
- (void)keyboardWillHide:(NSNotification*)notif {
if (_transitioningView)
return;
// Handle keyboard dismissal.
}