I have an iOS application with a settings.bundle that handles various settings for my application with Switch toggle. I set default values in my root.plist file (using the DefaultValue property) to YES but any time the application launches on a device or the iOS simulator all values go NO. It worked well only on the first launch.
I am retrieving the defaults with this code (am I doing something wrong here?):
NSUserDefaults *localeDefaults = [NSUserDefaults standardUserDefaults];
BOOL ENWORDS = [localeDefaults boolForKey:#"localetime"];
The Default Value is used by Settings.app for display purposes only. If you don't change the value in the settings app nothing is saved to NSUserDefaults.
You have to register the default values yourself. Use something like this in application:didFinishLaunchingWithOptions::
NSDictionary *userDefaultsDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], #"localetime",
nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:userDefaultsDefaults];
This blog post might help : http://greghaygood.com/2009/03/09/updating-nsuserdefaults-from-settingsbundle
tl;dr - until the user opens the settings page then the defaults aren't copied into your app. This is the expected behavior by Apple.
Personally, I think this is terrible. It means that you will have to set your defaults in code just in case the user starts your app without going to the settings page first (which will be true for about 99% of use cases!)
The problem is the type of default Value must be boolean not string ;) delete this value and add a another default Value property again
hope this helps
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//< Register Defaults
NSString *settingsBundlePath = [[NSBundle mainBundle] pathForResource:#"Settings" ofType:#"bundle"];
NSBundle *settingsBundle = [NSBundle bundleWithPath:settingsBundlePath];
NSString *rootPlistPath = [settingsBundle pathForResource:#"Root" ofType:#"plist"];
NSDictionary *settingsDict = [[NSDictionary alloc] initWithContentsOfFile:rootPlistPath];
NSArray *settingsItems = [settingsDict objectForKey:#"PreferenceSpecifiers"];
NSMutableDictionary *defaultDict = [NSMutableDictionary new];
for (NSDictionary *itemDict in settingsItems) {
if ([itemDict objectForKey:#"DefaultValue"]) {
[defaultDict setObject:[itemDict objectForKey:#"DefaultValue"] forKey:[itemDict objectForKey:#"Key"]];
}
}
[[NSUserDefaults standardUserDefaults] registerDefaults:defaultDict];
//< Following Code
}
You can check whether the value has been set by getting objectForKey and checking whether it is nil.
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
id dataExists = [userDefaults objectForKey:#"light_switch"];
BOOL lightSwitch;
if (dataExists != nil) {
lightSwitch = [userDefaults boolForKey:#"light_switch"];
NSLog(#"light_switch is %d", validateCertificates);
} else {
lightSwitch = YES; // default value
NSLog(#"light_switch not set, default value is %d", validateCertificates);
}
Related
I was using xCode 3.2 and then moved to xCode 4.2 and getting some values from Settings.bundle ... it was working fine.
Mean while I need to edit some values in Settings.bundle but The Root.plist file was not showing so I follow the below procedure but did not make any change in file.
1) Click on the Settings.Bundle file, go over to the utilities window,
and look in the File Inspector.
2) Using the drop-down, change the file type to 'Application Bundle'
After that I could see Root.plist but now could not get its values in application. Actually getting Null instead of value.
Below is code and image of Settings.bundle
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
host = [defaults stringForKey:#"meter_preference"];
if(host == nil)
{
host = #"10.20.20.1";
DDLogError(#"Meter host is nil from NSUserDefaults, defaulting to %#", host);
}
I got the solution, just call the below code in applicationDidFinishLaunchingWithOptions to initialize User defaults. and it works
Replace somePropertyYouExpect in first line with property you stored in User Defaults.
if (![[NSUserDefaults standardUserDefaults] objectForKey:#"somePropertyYouExpect"]) {
NSString *mainBundlePath = [[NSBundle mainBundle] bundlePath];
NSString *settingsPropertyListPath = [mainBundlePath
stringByAppendingPathComponent:#"Settings.bundle/Root.plist"];
NSDictionary *settingsPropertyList = [NSDictionary
dictionaryWithContentsOfFile:settingsPropertyListPath];
NSMutableArray *preferenceArray = [settingsPropertyList objectForKey:#"PreferenceSpecifiers"];
NSMutableDictionary *registerableDictionary = [NSMutableDictionary dictionary];
for (int i = 0; i < [preferenceArray count]; i++) {
NSString *key = [[preferenceArray objectAtIndex:i] objectForKey:#"Key"];
if (key) {
id value = [[preferenceArray objectAtIndex:i] objectForKey:#"DefaultValue"];
[registerableDictionary setObject:value forKey:key];
}
}
[[NSUserDefaults standardUserDefaults] registerDefaults:registerableDictionary];
[[NSUserDefaults standardUserDefaults] synchronize];
}
From your code , try this thinks..
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
host = [defaults stringForKey:#"meter_preference"];
if(!host == nil)
{
host = #"10.20.20.1";
DDLogError(#"Meter host is nil from NSUserDefaults, defaulting to %#", host);
}
OR
Review this link may be helped you...
iPhone - reading Setting.bundle returns wrong values
NSUserDefaults Settings Bundle Plist
I am encountering a strange issue in iOS 8.2 where [NSUserDefaults standardUserDefaults] is returning nil on iPhone. This same logic untouched has worked on all previous releases of iOS. I have a universal app which has two different settings.plist one for iPad and the other for iPhone list as follows;
Settings.bundle-
-Root.plist
-Root~iphone.plist
When installed on devices the correct settings pane displays and the user can input the appropriate values for the given fields. Though in my app at runtime [NSUserDefaults standardUserDefalts] returns a nil object.
What might I be doing wrong? Has Apple changed what is expected in 8.2?
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
userDefaults is always nil no matter what preferences are set in system settings.
Did you set the dictionary to use as "Settings.bundle/Root.plist"?
// Register the preference defaults from file "Settings.bundle/Root.plist"
NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfFile:
[[NSBundle mainBundle] pathForResource:#"Settings.bundle/Root"
ofType:#"plist"]];
[[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];
Thereafter [NSUserDefaults standardUserDefaults] no longer is nil.
In my case, the dictionary used by [NSUserDefaults standardUserDefaults] looks like this in the debugger:
{
PreferenceSpecifiers = (
{
DefaultValue = 1;
Key = sortByDistance;
Title = "Sortiere nach Entfernung";
Type = PSToggleSwitchSpecifier;
}
);
StringsTable = Root;
}
To access the preferences I've written a tiny method:
- (id) preferenceValueForKey: (NSString *)key {
NSArray *preferences = [[NSUserDefaults standardUserDefaults] arrayForKey:#"PreferenceSpecifiers"];
NSUInteger index = [preferences indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
return [[obj valueForKey:#"Key"] isEqualToString:key];
}];
return [preferences[index] valueForKey:#"DefaultValue"];
}
I have the following code. However, the line
stepper.value = [NSNumber numberWithDouble:loadNumber];
errors with the error 'Sending NSNumber *__strong to a parameter of incompatible type 'double''. I think the stepper will only accept a double, but am unsure what I am doing wrong to set it.
What I need to achieve is the following:-
1) Have a default value set in NSUserDefaults for saveNumber, which will be used until a variation is made by the user.
2) on load or view appearing, use saveNumber to set the value of both stepper.value and myLabel.
3) ensure that when changed with the stepper, the value is updated in myLabel, and NSUserDefaults saveNumber is also updated.
Can anyone advise where I am going wrong, and help correct my code please?
Further,I just realised that in the final app, I will have this setting on a different viewController to the one that will use the NSUserDefaults savedNumber value. With this in mind, can you also let me know how to ensure that savedNumber is available not only to this viewController, but any other one I require the values on?
Many thanks.
- (void)viewWillAppear:(BOOL)animated
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSNumber *loadNumber = [defaults objectForKey:#"saveNumber"];
self.myLabel.text = [NSString stringWithFormat:#"%#",loadNumber];
UIStepper *stepper = [[UIStepper alloc] init];
stepper.value = [NSNumber numberWithDouble:loadNumber];
}
- (IBAction)stepChanged:(id)sender {
NSNumber *saveNumber = [NSNumber numberWithDouble:[(UIStepper *)sender value]];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:saveNumber forKey:#"saveNumber"];
[defaults synchronize];
self.myLabel.text = [NSString stringWithFormat:#"%#",saveNumber];
}
I have one outstanding issue which is that I cannot get the defaults to deliver if no value has been set!
I have the following code in AppDelegate.m:-
NSDictionary *defaults = #{ #"saveNumber": #8 };
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
When the App first launches (and every time after until the stepper has been used) the value being seen is 'null'.
Any ideas?
This:
stepper.value = [NSNumber numberWithDouble:loadNumber];
needs to be:
stepper.value = [loadNumber doubleValue];
And you don't need to call synchronize after setting the value in NSUserDefaults.
A value stored in NSUserDefaults can be accessed from any class, not just the class that sets it.
Update:
To set a default value you want the following:
NSDictionary *defaults = #{ #"saveNumber": #6 };
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
This will set a default value of 6 for #"saveNumber".
I have the following code below which uses a stepper to set the value of the myLabel.
I have it set to store the value to NSUserDefaults.
1) I also need to set the stepper value to the same figure as that which I have put into the label. Can someone advise how to do this please? (I have added a comment to the code where I feel this should be.)
2) I would also like to check before loading the saveString that it is actually set, and if not, set a default value. Could you also advise how to achieve this?
Thanks.
- (void)viewWillAppear:(BOOL)animated
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *loadString = [defaults objectForKey:#"saveString"];
self.myLabel.text = loadString;
// Need to set the stepper value to that in loadString
}
- (IBAction)stepChanged:(id)sender {
NSString *saveString = [NSString stringWithFormat:#"%d",
[[NSNumber numberWithDouble:[(UIStepper *)sender value]] intValue]];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:saveString forKey:#"saveString"];
[defaults synchronize];
self.myLabel.text = saveString;
}
I have updated the code as follows:-
- (void)viewWillAppear:(BOOL)animated
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSNumber *loadNumber = [defaults objectForKey:#"saveNumber"];
self.myLabel.text = [NSString stringWithFormat:#"%#",loadNumber];
UIStepper *stepper = [[UIStepper alloc] init];
stepper.value = [NSNumber numberWithDouble:loadNumber];
}
- (IBAction)stepChanged:(id)sender {
NSNumber *saveNumber = [NSNumber numberWithDouble:[(UIStepper *)sender value]];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:saveNumber forKey:#"saveNumber"];
[defaults synchronize];
self.myLabel.text = [NSString stringWithFormat:#"%#",saveNumber];
}
However, the line 'stepper.value = [NSNumber numberWithDouble:loadNumber];' errors with the error 'Sending 'NSNumber *__strong" to a parameter of incompatible type 'double''. I think the stepper will only accept a double, but am unsure what I am doing wrong to set it.
What I need to achieve is the following:-
1) Have a default value set in NSUserDefaults for saveNumber, which will be used until a variation is made by the user.
2) on load or view appearing, use saveNumber to set the value of both stepper.value and myLabel.
3) ensure that when changed with the stepper, the value is updated in myLabel, and NSUserDefaults saveNumber is also updated.
Can anyone advise where I am going wrong, and help correct my code please?
Further, something I just realised as I am typing this is that in the final app, I will have this setting on a different viewController to the one that will use the NSUserDefaults savedNumber value. With this in mind, can you also let me know how to ensure that savedNumber is available not only to this viewController, but any other one I require the values on?
Many thanks.
Regarding question 1:
Just make one instance variable int stepper; (in your .h)
then in viewWillAppear set this variable as you do at the moment; and set
stepper = [defaults integerForKey:#"stepper"];
In your IBAction just call
stepper++;
self.myLabel.text = [NSString stringWithFormat:#"%i",stepper];
and save it in your NSUserDefaults.
Regarding question 2: NSUserDefaults offers the possibility to register defaults for certain keys, have a look at this:
NSDictionary *defaults = [NSDictionary dictionaryWithObjectsAndKeys:
#"test", #"key",
nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
If there is nothing set in the NSUserDefaults, the objectForKey method will return nil, so your loadString will be nil.
Now, you could convert the value you saved from a string into a number, something like [loadString floatValue];, but a probably better way would be to store an NSNumber into the userDefaults with the correct value, and recreate your label text with stringWithFormat method.
I'm using in-app settings from http://www.inappsettingskit.com/. It is really great but I can't figure out how to have the settings automatically load into the in-app settings on launch.
When I launch my app for the first time, all of the in-app multi-value cells are blank.
What I want to know is how to load them when the app is launched the first time?
The defaults are loaded in from the settings bundle, but aren't being passed through to the in-app settings...currently this is my code that does that...
-applicationDidFinishLaunching:
//It is here that we set the defaults
NSString *textValue = [[NSUserDefaults standardUserDefaults] stringForKey:#"title_key"];
//If the first value is nil, then we know that the defaults are not set.
if(textValue == nil)
{
//We set the default values from the settings bundle.
//Get the bundle path
NSString *bPath = [[NSBundle mainBundle] bundlePath];
NSString *settingsPath = [bPath stringByAppendingPathComponent:#"Settings.bundle"];
NSString *plistFile = [settingsPath stringByAppendingPathComponent:#"Root.plist"];
NSDictionary *settingsDictionary = [NSDictionary dictionaryWithContentsOfFile:plistFile];
NSArray *preferencesArray = [settingsDictionary objectForKey:#"PreferenceSpecifiers"];
NSDictionary *item;
NSString *title_Key;
NSString *detail_Key;
NSString *sort_Key;
for(item in preferencesArray)
{
//Get the key of the item.
NSString *keyValue = [item objectForKey:#"Key"];
//Get the default value specified in the plist file.
id defaultValue = [item objectForKey:#"DefaultValue"];
if([keyValue isEqualToString:#"title_key"]) title_Key = defaultValue;
if([keyValue isEqualToString:#"detail_key"]) detail_Key = defaultValue;
if([keyValue isEqualToString:#"sort_key"]) sort_Key = defaultValue;
}
//Now that we have all the default values.
//We will create it here.
NSDictionary *appPrerfs = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:2], #"title_key",
[NSNumber numberWithInt:4], #"detail_key",
[NSNumber numberWithInt:2], #"sort_key",
nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:appPrerfs];
[[NSUserDefaults standardUserDefaults] synchronize];
}
I have also tried the suggestion in the first answer, creating a seperate userDefaults.plist and have the defaults being loaded from there, my app is still getting the defaults but they are not passing through to in-app settings.
I thought that it should look like this on the first launching the app...
You want to register your NSUserDefaults first. Check out this description.