Failed to save double Value in NSUSerDefault - ios

Hi everybody :) i want to save a double Value into NSUserDefault like this:
NSUserDefaults *startValues = [NSUserDefaults standardUserDefaults];
[startValues setDouble:[[self.dataList objectAtIndex:indexPath.row]doubleValue] forKey:#"lat"];
[startValues synchronize];
I get no Errors or Warnings from Xcode, but when i run the Code, it crashes with the Message:
-[__NSCFDictionary doubleValue]: unrecognized selector sent to instance
I also tried to split up the Code like:
double lat = [[self.dataList objectAtIndex:indexPath.row]doubleValue];
[startValues setDouble:lat forKey:#"lat"];
but of course, i get the same error. Whats the Problem?
Thanks for your time and help :)

The problem is that [self.dataList objectAtIndex:indexPath.row] contains a dictionary. NSDictionary does not understand the doubleValue message.
You have to somehow extract the double value from the dictionary:
NSDictionary *dictionary = self.dataList[indexPath.row];
double value = [dictionary[#"latitude"] doubleValue];
[startValues setDouble:value forKey:#"lat"];

Related

Convert NSNumber to long

I am trying to convert a NSNumber to long but I get this error:
[__NSSingleObjectArrayI intValue]: unrecognized selector sent to
instance
Here is my code:
NSNumber *dbversion = [settings valueForKey:#"Version"];
long dbver = [dbversion longValue];
What am I doing wrong here?
*settings is a NSArray and "Version" is the key for a long value.
You are caught in the Key-Value Coding trap.
In some cases the result of valueForKey is an array which the error message clearly states.
Don't Never use valueForKey(unless you know what KVC does and you need KVC), use key subscription.
And as settings is an array you might get the first item
NSNumber *dbversion = settings[0][#"Version"];
and int is not long
long dbver = [dbversion longValue];
However on a 64-bit machine I recommend to use NSInteger
NSInteger dbver = dbversion.integerValue;
//I think you are storing string from dictionary "settings" to NSNumber so it's showing error like you mention in question.
Please Try with solution. May this help you.
NSNumber *dbversion = [NSNumber numberWithLong:[[settings valueForKey:#"Version"] longLongValue]];
int dbver = [dbversion longValue];

How would I be able to save an integer when an app is terminated and then load it again once the app is reopened?

I am working on an app where I need to save one int until the player decides to play the game again. It would be greatly appreciated if someone could guide me by using NSUserDefaults to save this integer whenever the application is terminated, and then be able to load it again as soon as the application loads. If there is any further information that is needed to help you help me just let me know! Thanks in advance!
You cannot save an int, you will need to convert it to an NSNumber. Use:
NSNumber *number = #(myInt);
Then you can save it (when the app terminates in your appDelegate's applicationWillTerminate:) using:
[[NSUserDefaults standardUserDefaults] setObject:number forKey:#"number"];
[[NSUserDefaults standardUserDefaults] synchronize];
To retrieve the value use:
NSNumber *number = [[NSUserDefaults standardUserDefaults] stringForKey:#"number"];
As pranav told you can store int as NSNumber or you can store it as a String, Following will work fine with NSNumber object,
int a = 10;
NSNumber *myNumber = [NSNumber numberWithInt:a];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:myNumber forKey:#"storedInt"];
NSLog(#"stored number object %#", [defaults objectForKey:#"storedInt"]); // retrieve value from NSUserDefaults
//then change NSNumber object to int value - if required
int retrievedInt = [myNumber intValue];
NSLog(#"int value %u", retrievedInt);

iOS UIStepper & NSUserDefaults - How to manage them together and use a double

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

UIStepper - Set value from NSUserDefaults

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.

Modifying NSDictionary in run Time [duplicate]

This question already has answers here:
Mutable Objects inside NSUserDefaults
(4 answers)
Closed 9 years ago.
Please Help me.
I have a plist clothingList.plist
I am accessing it like this in a method
NSString *path=[[NSBundle mainBundle] pathForResource:#"ClothingList" ofType:#"plist"];
//NSDictionary *ClothingAssets ; //Declared globally in .h file
ClothingAssets=[[NSMutableDictionary alloc]initWithContentsOfFile:path];
[[NSUserDefaults standardUserDefaults]setObject:ClothingAssets forKey:#"ClothingAssets"];
[[NSUserDefaults standardUserDefaults] synchronize];
Now I want to modfify a bool value in Clothing Assets Dictionary in another method.
ClothingAssets=[[NSUserDefaults standardUserDefaults] dictionaryForKey:#"ClothingAssets"];
[[[[[[ClothingAssets objectForKey:#"ClothingStore"] objectAtIndex:temp_Store]objectForKey:#"Assets" ]objectForKey:[NSString stringWithFormat:#"%#",temp_AssetType]] objectAtIndex:ii] setValue:#"YES" forKey:#"isLock"] ;
When I run the code For the first time it crashes and Show an error like this:
************ Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object'***
*** First throw call stack:
(0x1fb5012 0x29c5e7e 0x1fb4deb 0x1f7b347 0x3f39bf 0x435d9 0x41f76 0xea5020 0x29d9705 0xab5920 0xab58b8 0xb76671 0xb76bcf 0xb75d38 0xae533f 0xae5552 0xac33aa 0xab4cf8 0x3397df9 0x3397ad0 0x1f2abf5 0x1f2a962 0x1f5bbb6 0x1f5af44 0x1f5ae1b 0x33967e3 0x3396668 0xab265c 0x22ed 0x2225 0x1)
libc++abi.dylib: terminate called throwing an exception******
But When I run the code for second time it is working properly.
please help me.
There are many similar questions. From the exception its evident that you are trying to include a value to an immutable dictionary.
Unwrap the values one at a time and since you are going to edit them always make a mutableCopy
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableDictionary *clothingAssets=[[defaults dictionaryForKey:#"ClothingAssets"] mutableCopy];
NSMutableArray *clothingStores = [clothingAssets[#"ClothingStore"] mutableCopy];
NSMutableDictionary *clothingStore = [clothingStores[temp_Store] mutableCopy];
NSMutableDictionary *assets = [clothingStore[#"Assets"]mutableCopy];
NSString *assetTypesKey = [NSString stringWithFormat:#"%#",temp_AssetType];
NSMutableArray *assetTypes = [assets[assetTypesKey]mutableCopy];
NSMutableDictionary *assetType = [assetTypes[i] mutableCopy];
//Value is set
assetType[#"isLock"] = #"YES";
//Now you need to update the values back to the top most level
[assetTypes replaceObjectAtIndex:i withObject:assetType];
assets[assetTypesKey] = assetTypes ;
clothingStore[#"Assets"] = assets;
[clothingStores replaceObjectAtIndex:temp_Store withObject:clothingStore];
clothingAssets[#"ClothingStore"] = clothingStores;
[defaults setObject:clothingAssets forKey:#"ClothingAssets"];
[defaults synchronize];
Nested message sends aside, this is actually rather straightforward. When you see that error, it means you're trying to mutate an immutable object. The runtime throws a tantrum when you try to do that. Instead, do this:
ClothingAssets=[[NSUserDefaults standardUserDefaults] dictionaryForKey:#"ClothingAssets"];
NSDictionary *clothingStore = [ClothingAssets objectForKey:#"ClothingStore"];
NSArray *assets = [clothingStore objectForKey:#"Assets"];
NSDictionary *subAsset = [assets objectAtIndex: temp_Store];
NSArray *subAssetArray = [subAsset objectForKey: [NSString stringWithFormat:#"%#",temp_AssetType];
// At this point I'm afraid I run out of creative ways to describe your storage hierarchy:
NSDictionary *subAssetArraySubDictionary = [subAssetArray objectAtIndex: ii];
NSMutableDictionary *mutableCopy = [subAssetArraySubDictionary mutableCopy];
// And finally, set the value:
// Beware: This uses the string YES instead of a boolean value for YES - you need to remember this
// when accessing it later.
[mutableCopy setValue: #"YES" forKey: #"isLock"];

Resources