Xcode NSUserDefaults settings lost when app is force quit - ios

I'm using NSUserDefaults to save BOOLs that denote whether a mapped annotation is a "favorite". The BOOLs are saved correctly when the User quits the app and then re-launches it. However, when the User force quits (press the Home button twice and swipe up on the app) the app, the NSUserDefaults are lost. Can someone please explain why this is happening? I'm using Xcode v7.0.
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
// If annotation is displayed, the User can save/clear annotation as a favorite
if ((_acmeMotorsIsDisplayed == YES) && (_acmeMotorsIsFavorite == YES)){
_acmeMotorsIsFavorite = NO;
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:#"acmeMotorsIsFavorite"];
}
else if ((_acmeMotorsIsDisplayed == YES) && (_acmeMotorsIsFavorite == NO)){
_acmeMotorsIsFavorite = YES;
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"acmeMotorsIsFavorite"];
}
}
-(void)loadUserDefaults{
// One of many lines of code that load user default settings
_acmeMotorsIsFavorite = [[NSUserDefaults standardUserDefaults] boolForKey:#"acmeMotorsIsFavorite"];
}
-(void)viewDidLoad {
[self loadUserDefaults];
}

I think you forget about synchronize method.
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setBool:NO forKey:#"acmeMotorsIsFavorite"];
[userDefaults synchronize];

When the user double taps Home the app delegate method applicationWillResignActive: is called, at that time synchronize NSUserDefaults:
- (void)applicationWillResignActive:(UIApplication *)application {
[[NSUserDefaults standardUserDefaults] synchronize];
}

Related

iOS: Force view reload after locale change

I have setup my app to support a base internationalization for English and added a local for Spanish. I'm trying to provide an option to force the app to use a locale select by the user via a segmented control.
What I would like to do is have the screen "refresh" or "redraw" with the new selected locale.
Here is my action for the segmented control:
- (IBAction)segmentSwitch:(id)sender {
UISegmentedControl *segmentedControl = (UISegmentedControl *) sender;
NSInteger selectedSegment = segmentedControl.selectedSegmentIndex;
NSUserDefaults *prefs;
prefs = [NSUserDefaults standardUserDefaults];
if (selectedSegment == 0) {
[prefs setObject:#"en" forKey:#"language"];
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:#"en", nil] forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(#"English");
}
else
{
[prefs setObject:#"es" forKey:#"language"];
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:#"es", nil] forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(#"Spanish");
}
[self.view setNeedsDisplay];
}
My hope is that the screen would refresh and display the selected language view. If I close out the app and restart, it does display new view.
Here is my viewWillAppear:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// get the saved language preference
NSUserDefaults *prefs;
prefs = [NSUserDefaults standardUserDefaults];
NSString *stringVal = [prefs stringForKey:#"language"];
// Make sure we have a valid value
if (stringVal != nil) {
// Set the language preference
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:stringVal, nil] forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; //to make the change immediate
// Turn on the appropriate segment
if ([stringVal isEqual: #"en"]) {
NSLog(#"English");
languageSwitch.selectedSegmentIndex = 0;
} else {
NSLog(#"Spanish");
languageSwitch.selectedSegmentIndex = 1;
}
} else {
// default to English
languageSwitch.selectedSegmentIndex = 0;
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:#"en", nil] forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; //to make the change immediate
}
}
I had thought that following would force a screen refresh but it doesn't seem to be working:
[self.view setNeedsDisplay];
Any thoughts or suggestions would be appreciated. Thanks in advanced.

Settings page to show only once

I have an app which should only show the settings page once: when the app is opened for the first time.
Now this works, and when the user presses the middle button on the iPhone it then reopens the app and carries on from the main screen - that's great. But if I double click on the iPhone button and swipe the application off, it will then go to the settings screen again and not to where it was.
Why is it doing that? How can I make my app only show its settings once?
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
NSUserDefaults *settingsscreen = [NSUserDefaults standardUserDefaults];
[settingsscreen registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],#"firstTime", nil]];
BOOL firstTime = [settingsscreen boolForKey:#"firstTime"];
if ( firstTime==YES) {
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"SettingsShown"];
[[NSUserDefaults standardUserDefaults] synchronize];
self.window.rootViewController = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:#"SetUpNav"];
}
else
{
return YES;
}
}
Don't use if ( firstTime==YES) { based on #"firstTime", because that flag is never actually saved. You should be using the flag saved with the #"SettingsShown" key.
BOOL firstTime = [settingsscreen boolForKey:#"SettingsShown"];
if (!firstTime) {
...
Instead doing in appDelegate try to acheive it in setting Page itself
-(void) viewDidLoad {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
username = [defaults objectForKey:#"username"];
if (username != NULL ) {
[self selfLogin];
}
}
-(void)selfLogin{
nextPageController = [[NextPageViewController alloc]init];
[self.navigationController pushViewController:nextPageController animated:YES];
}

NSUserDefaults Saving only last entered data

I am saving Textfield text using NSUserDefaults on button click in ViewController2
My code is
ButtonClick()
{
NSUserDefaults *userDefaults =[NSUserDefaults standardUserDefaults];
[userDefaults setObject:keyWordField.text forKey:#"Keywords"];
[userDefaults synchronize];
}
Then ViewDidLoad method i am Retrieving like this
-(void)viewDidLoad
{
NSUserDefaults *userDefaults =[NSUserDefaults standardUserDefaults];
[keyWordArray addObject:[userDefaults objectForKey:#"Keywords"]];
[userDefaults synchronize];
}
Here i am assigning this keyWordArray to tableview
like cell.textlabel.text =[keyWordArray objectAtIndex:indexPath.row];
First i entered text(First) in textfield and click button it is showing in table like
First
Second time i entered text (second) in textfield and click button it is showing table like
First
Second
Here everything working fine. The problem is when i come to viewController2 from ViewController1. It is showing last entered value only
like
Second
what going wrong here?
Try This
- (IBAction)buttonclick:(id)sender {
[keyWordArray addObject:keyWordField.text];
NSUserDefaults *userDefaults =[NSUserDefaults standardUserDefaults];
[userDefaults setObject:keyWordArray forKey:#"Keywords"];
[userDefaults synchronize];
[selt.tableView reload]; //reload the table every time a new text is added
}
-(void)viewDidLoad {
if([[NSUserDefaults standardUserDefaults] objectForKey:#"Keywords"]==nil){
keyWordArray = [[NSMutableArray alloc] init];
}
else{
keyWordArray = [[NSUserDefaults standardUserDefaults] objectForKey:#"Keywords"];
}
}
Try this,
- (IBAction)buttonclick:(id)sender {
[keyWordArray addObject:keyWordField.text];
NSUserDefaults *userDefaults =[NSUserDefaults standardUserDefaults];
[userDefaults setObject:keyWordArray forKey:#"Keywords"];
[userDefaults synchronize];
}
and
-(void)viewDidLoad
{
NSArray *array = [[NSUserDefaults standardUserDefaults] objectForKey:#"Keywords"];
if (!array) {
keyWordArray = [[NSMutableArray alloc] init];
} else {
keyWordArray = [NSMutableArray arrayWithArray:nameArray];
}
}
Since you are overriding your
[userDefaults setObject:keyWordField.text forKey:#"Keywords"];
every then and there your every object in the array will be referring to your [userDefaults setObject:keyWordField.text forKey:#"Keywords"]; object thats y the problem comes
Because if you are navigate to another viewController. since the your user default value save in second only.
After pop to back through viewDidLoad is loaded. so far its have second string only save in User Default.
that way it display second only.
You code is overwrite the last value and remove previous values from NSUserDefault. You have to use array to stored all value and you have save array into NSUserDefault.
NSMutableArray *aryDataDefault = [[NSUserDefaults standardUserDefaults] valueForKey:#"YourKey"];
[aryDataDefault addObject:textfield.text];
[[NSUserDefaults standardUserDefaults] setObject:aryDataDefault forKey:#"YourKey"];
[[NSUserDefaults standardUserDefaults] synchronize];

Detect if user opened the View for the first Time In iOS

I know how I can detect if the application first time opened using NSUserDefault:
BOOL didRunBefore = [[NSUserDefaults standardUserDefaults] boolForKey:#"didRunBefore"];
if (!didRunBefore) {
//Your Launch Code
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"didRunBefore"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
The Issue: I want an Alert for ever view explaining about what features it contains and only open this alert when the app is first launched?
As an OOP programmer you can make a common public method.
+ (BOOL)checkWhetherRunBefore:(NSString *)key
{
return [[NSUserDefaults standardUserDefaults] boolForKey:key];
}
+ (void)hasRunForMyClass:(NSString *)key
{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:key];
[[NSUserDefaults standardUserDefaults] synchronize];
}
And in your ViewController , you can code in the viewWillAppear or viewDidAppear like this :
- (void)viewWillAppear
{
if(![HelpController checkWhetherRunBefore:NSStringFromClass([self class])])
{
//do your thing
[HelpController hasRunForMyClass:NSStringFromClass([self class])]
}
}
You just need to put your code in viewDidLoad
viewDidLoad will run only one time when app load your view. (except low memory)
Next time you load the view again in viewDidLoad, you can check bool didRunBefore
You can use any key you want.
In FirstViewController:
BOOL didRunBefore = [[NSUserDefaults standardUserDefaults] boolForKey:#"FirstViewController_didRunBefore"];
if (!didRunBefore) {
//Your Launch Code
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"FirstViewController_didRunBefore"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
In SecondViewController:
BOOL didRunBefore = [[NSUserDefaults standardUserDefaults] boolForKey:#"SecondViewController_didRunBefore"];
if (!didRunBefore) {
//Your Launch Code
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"SecondViewController_didRunBefore"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
yo have to need to detect application first launch, you can detect t like this
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (![defaults objectForKey:#"firstRun"])
[defaults setObject:[NSDate date] forKey:#"firstRun"];
[[NSUserDefaults standardUserDefaults] synchronize];
You can then test for it later...
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if([defaults objectForKey:#"firstRun"])
{
// do something or not...
}

Setting/Saving UISwitch State using NSUserDefaults Proofread

Developing for a jailbroken device.
I've looked here for a soultion to my problem. Using NSUserDefaults for storing UISwitch state but people say alot of the codes don't work.
I'm using a UISwitch to load/unload a launch daemon for iOS. I've gotten very close but the switch state won't save. This is the code im using.
#synthesize toggleSwitch;
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if([[NSUserDefaults standardUserDefaults] boolForKey:#"switch"]) toggleSwitch.on = [[NSUserDefaults standardUserDefaults] boolForKey:#"switch"];
}
- (void)switchValueChanged {
if (toggleSwitch.on) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:TRUE];
switchlabel.text = #"Enabled";
const char *onchar = [[NSString stringWithString:#"launchctl load -wF /System/Library/LaunchDaemons/com.launch.daemon.plist"] UTF8String];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:FALSE];
setuid(0); system(onchar);
if (system(onchar) == 0){
[[NSUserDefaults standardUserDefaults] setBool:self.toggleSwitch.on forKey:#"switch"];
[[NSUserDefaults standardUserDefaults] synchronize];
} else {
[[NSUserDefaults standardUserDefaults] setBool:self.toggleSwitch.on forKey:#"switch"];
[[NSUserDefaults standardUserDefaults] synchronize];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:FALSE];}
} else {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:TRUE];
switchlabel.text = #"Disabled";
const char *offchar = [[NSString stringWithString:#"launchctl unload -wF /System/Library/LaunchDaemons/com.launch.daemon.plist"] UTF8String];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:FALSE];
setuid(0); system(offchar);
if (system(offchar) == 0){
[[NSUserDefaults standardUserDefaults] setBool:self.toggleSwitch.on forKey:#"switch"];
[[NSUserDefaults standardUserDefaults] synchronize];
} else {
[[NSUserDefaults standardUserDefaults] setBool:self.toggleSwitch.on forKey:#"switch"];
[[NSUserDefaults standardUserDefaults] synchronize];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:FALSE]; }
}
The bool value is written in my app plist. I don't seem to know what I did wrong. I pieced afew examples from questions on overflow with no luck. Regardless if the command fails, the switch should save.
Could someone explain and show me what should be edited. This has been driving me absolutely nuts.

Resources