NSUserDefaults registerDefaults with NSInteger - ios

I am using NSUserDefaults to store some integer settings for my app, but I want to register default values for these settings, using code like this:
NSDictionary *appDefaults = [[NSDictionary alloc] initWithObjectsAndKeys:(NSInteger)0, #"PMChordColour", (NSInteger)1, #"PMTextColour", (NSInteger)0, #"PMBackgroundColour", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults];
The values are read in my app using
NSInteger setColour = [[NSUserDefaults standardUserDefaults] integerForKey:#"PMChordColour"];
The problem with this is that NSDictionary does not allow scalar values to be stored.
Is there any way of registering defaults that allows integers to be stored? I realise that I could use NSNumber but it seems like unnecessary overhead.

No, you have to use NSNumber. It's necessary overhead.

NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:13], #"id", nil];
int integer = [[dict objectForKey:#"id"] intValue];

Related

NSNumber numberWithBool changing the value of boolean from plist file

I have a plist file with the a key APICalls of type boolean set to NO.
I then retrieve this value in my code like this:
NSString *destinationPath= [doumentDirectoryPath stringByAppendingPathComponent:#"DefaultSettings.plist"];
NSMutableDictionary *defaultPreferences = [NSMutableDictionary dictionaryWithContentsOfFile:destinationPath];
NSLog(#"SETUP %#", defaultPreferences);
[[NSUserDefaults standardUserDefaults] registerDefaults:defaultPreferences];
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *tmp = [data objectForKey:#"user"];;
user.email = [tmp valueForKey:#"email"];
user.userId = [tmp valueForKey:#"id"];
user.username = [tmp valueForKey:#"username"];
user.APICall = [NSNumber numberWithBool:[defaults objectForKey:#"APICalls"]];
NSLog(#"API Call Value: %#", user.APICall);
My first log returns :
SETUP {
APICalls = 0;
TrackingTimer = 15;
VoiceMessages = 0;
}
Showing me the value of APICalls is 0.
But when I log user.APICall, I get
API Call Value: 1
Also user.APICall is of type NSNumber.
The problem is that objectForKey: of NSUserDefaults returns a cocoa object - in this case, it is probably an NSNumber. When you pass it to numberWithBool: method, it treats nil as NO, and everything else as YES.
If APICalls is set as a boolean, you can use it directly, like this:
user.APICall = [defaults objectForKey:#"APICalls"];
If APICalls is a number that you would like to re-interpret as a boolean, you can use this line instead:
user.APICall = [NSNumber numberWithBool:[[defaults objectForKey:#"APICalls"] intValue] != 0];
Don't forget to call [userDefaults synchronise].

writing data into firebase using an iphone app

This was the question I had asked in order to write data into firebase through an android app, I want to represent the information in the same way in an iphone app.
I am using a dictionary to represent the key-value pairs.
f = [[Firebase alloc] initWithUrl:#"https://ums-ios.firebaseio.com/"];
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
#"latitude",[[NSNumber numberWithFloat:latitude] stringValue],
#"longitude",[[NSNumber numberWithFloat:longitude] stringValue],
#"timestamp",[[NSNumber numberWithDouble:timeStamp] stringValue],
nil];
Firebase* tempRef = [f childByAppendingPath:#"mobileNum"];
[tempRef setValue:dictionary];
I am getting an exception when I try to run this. But when I replace the NSDictionary with NSArray my data is getting mapped to array indices, which is not what I would require.
any suggestions ?
I think it's unrelated, butyour dictionary is backwards. I also find it terribly annoying, and I feel like I always have to double check, but values come before keys for iOS
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
[[NSNumber numberWithFloat:latitude] stringValue], #"latitude",
[[NSNumber numberWithFloat:longitude] stringValue], #"longitude",
[[NSNumber numberWithDouble:timeStamp] stringValue], #"timestamp",
nil];
The full code would be this
float latitude = 30.472;
float longitude = 42.467;
double timeStamp = NSTimeIntervalSince1970;
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
[[NSNumber numberWithFloat:latitude] stringValue], #"latitude",
[[NSNumber numberWithFloat:longitude] stringValue], #"longitude",
[[NSNumber numberWithDouble:timeStamp] stringValue], #"timestamp",
nil];
Firebase * f = [[Firebase alloc]initWithUrl:#"https://ums-ios.firebaseio.com/"];
Firebase* tempRef = [f childByAppendingPath:#"mobileNum"];
[tempRef setValue:dictionary];
This will create the following URL scheme (added .json so you can see easy)
https://ums-ios.firebaseio.com/mobileNum/.json = the dictionary
https://ums-ios.firebaseio.com/mobileNum/latitude/.json = value for latitude
https://ums-ios.firebaseio.com/mobileNum/longitude/.json = value for longitude
https://ums-ios.firebaseio.com/mobileNum/timestamp/.json = value for timestamp
A note on security,
I just saved this data to your firebase, make sure you update security before releasing!

NSUserDefaults. Retrieving incorrect values

I am saving few dictionaries in NSUserDefaults this way:
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"event_states"] == nil)
{
NSDictionary *dict0 = [NSDictionary dictionaryWithObjectsAndKeys:
#"923381DC-3DCB-46CA-A6CF-C58A7AF33B89",#"guid",
#"В планах",#"name", //this string will returned corrupted
[NSNumber numberWithInt:12632256],#"color",
[NSNumber numberWithInt:0],#"isclosed",
[NSNumber numberWithInt:0],#"isfinish",
nil];
// and few more dictionaries same way
....
[[NSUserDefaults standardUserDefaults] setObject:#[dict0,dict1,dict2,dict3] forKey:#"event_states"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
NSArray *event_states = [[NSUserDefaults standardUserDefaults] objectForKey:#"event_states"];
When I am retrieving this data I am logging it and have a strange behavior. In some cases I am retrieving a correct value as this:
name = "\U0412 \U043f\U043b\U0430\U043d\U0430\U0445"
but in some cases as this:
name = "\U0412\U044b\U043f\U043e\U043b\U043d\U0435\U043d(\U043e)
and this last part in parenthesis is an extra symbol and I can't understand why it appears and what is dependence on when it appears and when it's not. What can be wrong with this?
I tried to convert your unicode to readable string and paste it in google translate
\U0412 \U043f\U043b\U0430\U043d\U0430\U0445 => В планах => The plans
\U0412\U044b\U043f\U043e\U043b\U043d\U0435\U043d(\U043e) => Выполнен(о) => Complete ?
So I think this happened because your code not the API.

InAppSettings not populating on launch

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.

Setting bundle default value won't set

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);
}

Resources