How to quit an iPhone app nicely? - iphone

or "How to simulate a home button pressed event?"
I need to restart my iPhone app, and I want the program to quit, so the user will only have to start it.
If I simply use exit(0) some changes won't get saved, as they would if the user quits by pressing the home button.
The restart needed for language change.
Related code:
- (void)onChangeLanguage: (id)sender {
NSArray *lang = [NSArray arrayWithObjects:((Whatever *)sender).newLanguage, nil];
[[NSUserDefaults standardUserDefaults] setObject:lang forKey:#"AppleLanguages"];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSArray *languages = [defaults objectForKey:#"AppleLanguages"];
NSString *currentLanguage = [languages objectAtIndex:0];
NSLog(#"Current language: %#", currentLanguage);
// ***
}
If the user restarts using the home button, language will change.
If // *** is replaced by exit(0), the language won't change.

Calling exit(0) is the only legal (but highly not recommended) way to exit the program from your code.
As a possible workaround you can show UIAlertView with no buttons that cannot be dismissed (forcing user to quit your program manually) and telling the user that he has to do that to apply your changes.

I think it’s perfectly fine to call exit, just call [[NSUserDefaults standardUserDefaults] synchronize] before you do that. You can read about the synchronize method in the Apple Documentation:
Because this method is automatically
invoked at periodic intervals, use
this method only if you cannot wait
for the automatic synchronization (for
example, if your application is about
to exit) or if you want to update the
user defaults to what is on disk even
though you have not made any changes.

It's worth noting that there's a private API call, too. Of course, all the usual warnings about using private APIs apply.
[[UIApplication sharedApplication] terminate];

Related

How to make scollView (for T&C) only show up once at begin of app, then never show up again?

My questions is...how to make....this...
I am trying to make a scollview to show the term&condition at beginning of my app when the user is 1st time using the app.
if the user accepted the T&C (by clicking accept button), this T&C scollview will never show up again at beginning of the app, as he already accepted. So he will be free to use the app in future.
How do I implement this? any suggestions?
Use NSUserDefaults with a key like "TCShown". If the key does not exist in the NSUserDefaults at the beginning of the launch, you show the T&C and create "TCShown" value, set it to YES ([NSNumber numberWithBool:YES];) and store it to the NSUserDefaults.
Edit:
Assuming that you want to present the T&C in your first viewController,
#define kTCViewedFlag = #"tcViewed"
-(void) viewDidAppear {
NSUserDefaults *myDefaults = [NSUserDefaults standardUserDefaults];
if(![myDefaults objectForKey:kTCViewedFlag]) {
//show the TC
}
}
-(IBAction) userAcceptedTC {
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:YES] forKey:kTCViewedFlag];
[[NSUserDefaults standardUserDefaults] synchronize];
//dismiss the scrollView
}
-(IBAction) userDidDeclineTC {
//handle refusal of TC
}
In addition to Kaan's answer, you can add the TCShown field to the server and update the values accordingly. This will take care of the case when the user who has already accepted the T&C's logs in from a different device.
Maybe you'll find this useful: RLAgreement View Controller
This project allows developers to include
and Agreement, Terms of Service, Non Disclosure Agreement, etc. to an
iPhone App. The controller stores a variable in the user's settings
when the user has a valid agreement and it checks every time the user
opens the App.

Consistent NSUserDefaults saving

So in my app, I was saving some integer keys in NSUserDefaults,like around a minimum of 20.
Something like this but many:
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setInteger:1 forKey:#"game1"];
[prefs setInteger:1 forKey:#"game2"];
[prefs setInteger:1 forKey:#"game3"];
So I was just wondering, should I call:
[[NSUserDefaults standardUserDefaults] synchronize];
Everytime I save?
Because sometimes I'm experiencing an inconsistency of the integer I'm saving and have been loading either with stopping, running the app in xCode or from the Home Button.
I have read a couple of articles on a site that stated:
In iOS4, your User Defaults may not get saved when pressing the home button. Manually calling [[NSUserDefaults standardUserDefaults] synchronize] in applicationDidEnterBackground: should ensure that your User Defaults is saved correctly.
Is this true and the same in iOS5? Or are there more accurate ways, shorter ways of saving integers. Thanks for the help.
Apple's documentation says this:
"Because this method is automatically invoked at periodic intervals, use this method only if you cannot wait for the automatic synchronization (for example, if your application is about to exit) or if you want to update the user defaults to what is on disk even though you have not made any changes."
So, depending on the urgency of the data you are settings, you may of may not need to call synchronize. Full documentation is here.
No you don't need to, when you call setInteger:forKey: on prefs, it automatically gets saved.

Storing Last Launch

I am trying to store the last launch date of my app. So I did the following:
- (void)applicationWillResignActive:(UIApplication *)application {
NSDate *today = [NSDate date];
[[NSUserDefaults standardUserDefaults] setObject:today forKey:#"lastLaunch"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
However, when I relaunch the app again and print out the object for key lastLaunch it shows null. Why isn't it storing the date? Am I putting it in the wrong method? I am running it and terminating the app from Xcode.
applicationWillResignActive: is also called when you receive phone call...
You can find more info here:
http://www.cocoanetics.com/2010/07/understanding-ios-4-backgrounding-and-delegate-messaging/
I think that applicationDidEnterBackground is a better place to put your code because user can deny phone call and go back to your app...
And for iOS3 users without multitasking watch for applicationWillTerminate:
Stop in Xcode just kills your application without calling anything...
NSUserDefaults is weird in the iPhone simulator. I expect your code to work on an actual device.

Update UI on settings change - Objective-C

For my application, I am storing a url in a settings panel so the user is able to edit it.
After the application is already open, I want to take care of the use case where the user presses the home button to background the application, goes into the settings panel, changes the url, and then wakes the application back up. The problem I am running into is when the application wakes back up and I try and get the value from the settings again, it is the same. The application only notices the change if the app is fully exited and then restarted.
Currently I am reading the settings like this:
NSUserDefaults *settings = [NSUserDefaults standardUserDefaults];
NSString *url = [settings stringForKey:"#url"];
This is wrapped inside of a function that gets invoked when UIApplicationDidBecomeActiveNotification gets fired.
Try to synchronize the defaults after setting the value :
[settings synchronize];

applicationWillTerminate works as long as I don't switch off the iPhone

to save some variables of my apps I use:
-(void)applicationWillTerminate:(UIApplication *)application {
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setFloat: self.viewController.sLabel.contentOffset.y forKey:#"floatKey"];
[prefs setObject:self.viewController.newText forKey:#"stringVal"];
[prefs synchronize];
}
and to retrieve them, via a button, I do the following:
-(IBAction) riprendi:(id) sender {
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
float myFloat = [prefs floatForKey:#"floatKey"];
//some actions here
}
Everything is working on the simulator. However, using it on a real iPhone, the variables' saving and retrieving works just if you press the Home button, exiting the app and opening again but NOT if you switch off/on the iPhone. In this case, the variables get simply lost once you re-open the app...
What am I missing?? This is actually driving me crazy :(
Thank you so much ;)
Fabio
If you mean hitting the lock button on the top of the phone by saying "switching on/off", then it won't work, because locking the phone does not cause an application to quit.
Your applicationWillTerminate: method is only called when you exit you're application to the home screen or to some other application. When the user presses the Sleep button, applicationWillResignActive: will be send to your application-delegate.
Apple's iPhone OS Programming Guide has a section on handling interruptions.
According to Apple's documentation
"NSUserDefaults caches the information to avoid having to open the user’s defaults database each time you need a default value."
If you want to make sure things are saved you should call "synchronize" on your prefs.