NSNumber numberWithBool changing the value of boolean from plist file - ios

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].

Related

iOS - NSUserdefaults always nil [duplicate]

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

iOS 8.2 [NSUserDefaults standardUserDefaults] returning nil

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"];
}

NSUserDefaults if data equal to something then NSLog

I created a simple app when you click on a button it saves first click with 1 second with 1 and so. So, I tried to check if the first click equal to 1 then NSLog but it didn't worked.
Here's my code:
-(IBAction)add:(id)sender
{
//Once the user click on the button it adds 1
static int num = 0;
num+=1;
//Save the number for key "saved and the number" ex: if number is 1 so for key is "saved 1"
NSString *dataa = [NSString stringWithFormat:#"%i", num];
NSString *fkey = [NSString stringWithFormat:#"saved %i", num];
NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
[def setObject:dataa forKey:fkey];
[def synchronize];
}
-(IBAction)load:(id)sender
{
//load the data forkey "saved 1" wich will be '1'
NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
NSString *loadd = [def objectForKey:#"saved 1"];
NSLog(#"%#",loadd);
//and here I failed, here I want to check if [def objectForKey:#"saved 1"] == '1'
//then NSLog#"Yes" but it NSLogs "NOO"
NSString *no = #"1";
if(loadd == no){
NSLog(#"YES");
}else{
NSLog(#"NOO");
}
}
So what is the issue here?
Thanks in Advance
use [loadd isEqualToString:no] instead, that compares strings.
here is the documentation link

NSUserDefaults registerDefaults with NSInteger

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];

Add values in NSMutableDictionary in iOS with Objective-C

I'm starting objective-c development and I would like to ask the best way to implement a list of keys and values.
In Delphi there is the class TDictionary and I use it like this:
myDictionary : TDictionary<string, Integer>;
bool found = myDictionary.TryGetValue(myWord, currentValue);
if (found)
{
myDictionary.AddOrSetValue(myWord, currentValue+1);
}
else
{
myDictionary.Add(myWord,1);
}
How can I do it in objective-c? Is there equivalent functions to the above mentioned AddOrSetValue() or TryGetValue()?
Thank you.
You'd want to implement your example along these lines:
EDIT:
//NSMutableDictionary myDictionary = [[NSMutableDictionary alloc] init];
NSMutableDictionary *myDictionary = [[NSMutableDictionary alloc] init];
NSNumber *value = [myDictionary objectForKey:myWord];
if (value)
{
NSNumber *nextValue = [NSNumber numberWithInt:[value intValue] + 1];
[myDictionary setObject:nextValue forKey:myWord];
}
else
{
[myDictionary setObject:[NSNumber numberWithInt:1] forKey:myWord]
}
(Note: you can't store ints or other primitives directly in a NSMutableDictionary, hence the need to wrap them in an NSNumber object, and make sure you call [myDictionary release] when you've finished with the dictionary).
The other answers are correct, but there is more modern syntax for this now. Rather than:
[myDictionary setObject:nextValue forKey:myWord];
You can simply say:
myDictionary[myWord] = nextValue;
Similarly, to get a value, you can use myDictionary[key] to get the value (or nil).
Yep:
- (id)objectForKey:(id)key;
- (void)setObject:(id)object forKey:(id)key;
setObject:forKey: overwrites any existing object with the same key; objectForKey: returns nil if the object doesn't exist.
Edit:
Example:
- (void)doStuff {
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:#"Foo" forKey:#"Key_1"]; // adds #"Foo"
[dict setObject:#"Bar" forKey:#"Key_2"]; // adds #"Bar"
[dict setObject:#"Qux" forKey:#"Key_2"]; // overwrites #"Bar"!
NSString *aString = [dict objectForKey:#"Key_1"]; // #"Foo"
NSString *anotherString = [dict objectForKey:#"Key_2"]; // #"Qux"
NSString *yas = [dict objectForKey:#"Key_3"]; // nil
}
Reedit: For the specific example there exists a more compact approach:
[dict
setObject:
[NSNumber numberWithInteger:([[dict objectForKey:#"key"] integerValue] + 1)]
forKey:
#"key"
];
Crazy indentation for readability.

Resources