Remove Modal View Controller when Application becomes active - iphone

In my app I have a button, when the user clicks it, it brings up a modal view controller which gets the user's location (with a UIActivityIndicator and image on). When it has there location it will send them off to another application.
This works well on older devices (without multi-tasking) because the app simply re-launches back to it's previous state after I go back to it.
However on devices that have multi-tasking, when I resume the app, the view that tells the user it's getting their location is still there - which is not at all desired.
My first idea was to set a BOOL when it was about to fire them off to the other app, and then in the viewDidAppear, if the BOOL is true, dismiss the modal view.
That would work, if viewDidAppear got called when an app resumes active. As I have just learnt, it doesn't.
Is there a method that view controllers can respond to when the app resumes active to that view? Or, will I have to set up delegation etc with the app delegate? If so, can you explain how I would do that?

You can send a notification when the app becomes active and listen to it into your modalviewcontroller. I think this is the easiest way.
// Into the app delegate
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"ApplicationDidBecomeActive" object:nil];
}
// Into your modal view controller register it for the given notification
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationDidBecomeActive:) name:#"ApplicationDidBecomeActive" object:nil];
- (void)applicationDidBecomeActive:(NSNotification *)notification
{
//...
}
Otherwise you can disable the background mode of your application by setting the "UIApplicationExitsOnSuspend" key to YES in the info.plist file.

Related

iPhone applicationWillResignActive - how to notify current UIView

I want to pause a timer on my game screen when the iPhone is locked etc. My question is what is the best method to notify the current UIView, which the AppDelegate has no direct access to?
1) Your timer should probably not be managed by the view but by the view's controller. The timer itself is not an inherent part of your UI, only the timer's display is. (What happens if you want to have the timer continue after a view is removed, for example?)
2) Any object (view or controller included) can independently listen for the appropriate notification. For example, in your view controller (or view code, if you choose to go that route):
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(pauseTheTimer:)
name:UIApplicationWillResignActiveNotification
object:nil];
Then implement a pauseTheTimer: method that will handle the notification. (Since there is only one UIApplication object, you can use nil for the object, as shown.)
This approach nicely decouples your app delegate from the views and view controllers.
(Oh, don't forget to stop observing when your view is unloaded or deallocated. Failure to do so can and will lead to crashes.)

What gets called after UIApplicationDidBecomeActiveNotification gets triggered?

In my app I'm trying to make my navigation bar not shrink from 44px to 32px when the phone is rotated to horizontal orientation. I've been able to accomplish this by setting the navigationBars frame when the view is rotated and also in viewDidAppear. However, when I push the home button to exit the app and then I reenter the app, the navigation bar still shrinks. So I implemented a notification to detect UIApplicationDidBecomeActiveNotification, and in that method I reset the navigationBar frame height to 44px. However, it doesn't work because something is getting called which is resetting my views frame. Does anyone know what gets called after a UIApplicationDidBecomeActiveNotification gets triggered that resets the viewcontrollers frame?
In Your application any class can be an "observer" for different notifications. When you create view controller, you can register it as an observer for the UIApplicationDidBecomeActiveNotification and specify which method that you want call when that notification gets sent your your application.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(myMethod:) name: UIApplicationDidBecomeActiveNotification object:nil];
remove observer in ViewWillDisappear/viewDidDisAppear/Dealloc as per your need:
[[NSNotificationCenter defaultCenter] removeObserver:self];
I'm having the same problem, if you attach an observer via Key Value Observers you can see that something is called after the UIApplicationDidBecomeActiveNotification.

App in foreground and background

I have a button ON/OFF in my viewcontroller that plays some music when it is turned on by the user. Now if the user clicks the iPhone home button and re-launches my app again, the button is shown as "ON" but there is no music playing. So the user has to hit ON-OFF-ON again for music to start playing again.
Anyone know how can I call my ON/OFF view controller button so that I can set it to OFF when app enters background and set it to ON and play the music when it enters forground in these app delegates?
I know I need to write to a plist file the button & music state on applicationDidEnterBackground. I don't know how can I get to those action from appdelegate since they are defined in my viewcontroller.
Similary, when the app enters the foreground I will read the saved plist file and then set the state of music and button again. Again, I don’t know how to call my controller methods from delegate.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
NSLog(#"Inside applicationDidEnterBackground");
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
NSLog(#"Inside applicationWillEnterForeground");
}
One possible methodology is to send a message from the app delegate to the view controllers to save or restore state. Then the view controller, which have access to their internal state, can implement any needed save and restore methods.
If the app delegate does not directly contain a reference to the active view controller, it can send the message down the chain, to root view controller, which can then send a message to the next view controller, and etc., each controller saving anything it considers important on the way down.
All you need to do is subscribe to the UIApplicationDidEnterBackgroundNotification notification in your view controller
[[NSNotificationCenter defaultCenter] addObserver: self
selector: #selector(handleEnteredBackground:)
name: UIApplicationDidEnterBackgroundNotification
object: nil];
Theres also a notification for DidEnterForeground too.

How apply Setting changes at restart?

I work on a project on iPhone iOS 4 with Xcode 4.
I have a view with a UIButton. The title of the UIButton is set in viewDidLoad. So when app starts, the Button has a title.
However, my app has a Settings bundle and the button title can be also changed in Settings app. So I clic on the home button, my app quits, I go to the Settings app, and set a new button title.
When I quit Settings and restart my app, the button title is not refreshed, it is the old button title. Everything is as I had left.
Only if I turn off the iPhone, then turn on and relaunch my app (i.e. at full restart) the button has at the new title.
How to make sure that the button title changes when the app is (not full) restarted?
Thank you.
You want to update the settings in applicationDidEnterForeground. That gets called when it resumes.
Edit: Had a typo, it should be
- (void)applicationWillEnterForeground:(UIApplication *)application
see docs: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIApplicationDelegate_Protocol/Reference/Reference.html
I was mistaken in thinking that the viewWillAppear message would be sent to the ViewController when the app became active again after switching back from the Settings app. There is a notification posted when the app becomes active, however, so you should be able to accomplish what you want by registering your ViewController to receive UIApplicationDidBecomeActiveNotification notifications:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(refreshButtonTitle:) name:UIApplicationDidBecomeActiveNotification object:nil];
and then create the appropriate method in your ViewController to be called when the notification is fired:
- (void)refreshButtonTitle:(NSNotification *)notification {
// update the title of your button here
}
You can register to receive NSUserDefaultsDidChangeNotifications and then act accordingly to update your UI.

App Delegate - Unload View Controller

I'm trying to unload a view controller from view when the iPhone goes to sleep. My app has a stopwatch that has to keep counting when the phone goes to sleep or call comes in or the user closes the app without logging out.
I have all this functionality in place, I'm capturing all start times and stop times and upon re-entering the stopwatch view controller, I calculate the difference. It all works beautifully. When I was doing some additional testing I realised I hadn't catered for the iPhone going into sleep mode.
So all I need to do to make sure my stopwatch is correct bring the user back to the app home screen. I know the following method is called when the app goes to sleep:
-(void)applicationWillResignActive:(UIApplication *)application
How do I unload the stopwatch view controller from my app delegate ?
---- UPDATE ----
kpower, thanks for your feedback. I've implemented the following code:
In my App Delegate:
- (void)applicationWillResignActive:(UIApplication *)application
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"AppIsAsleep" object:nil];
}
In my view controller, I have the following:
-(void)viewDidLoad
{
// Add Observer.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(viewDidUnload:) name:#"AppIsAsleep" object:nil];
}
- (void)viewDidUnload {
//Remove the Observer.
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"AppIsAsleep" object:nil];
}
When the phone goes to sleep, it actually closes the app, am I doing something wrong ?
Regards,
Stephen
You can use the Notifications mechanism. It allows you to unload view controller from different place (not the AppDelegate) this case.
For example, in your view controller's viewDidLoad method you add an observer (don't forget to remove it in viewDidUnload) and in applicationWillResignActive: method of AppDelegate you just simply post notification. That's all.
↓ Update here ↓
When you get a notification - you should manage view controller's removing by yourself. And calling viewDidUnload here is not the solution, cause this method is called after view controller was already unloaded and doesn't cause removing.
How to remove? Depends on how the view controller was added (for example, popViewControllerAnimated for UINavigationController). The main idea here is to make object's retain count equal to 0 (as you know this case an object will be destroyed) - so you should sent release message necessary amount of times.