Crash while fetching NSUserDefaults - iphone

The following code is crashing for me
[[NSUserDefaults standardUserDefaults] dictionaryForKey:#"2453"];
I checked and found that there is no key with name 2453 in NSUserDefaults. I am running the application for first time so this key will not be there but will be added later point in time. How to ignore this crash.

If this line
[[NSUserDefaults standardUserDefaults] dictionaryForKey:#"2453"];
is the line that is crashing, you might try this instead
NSDictionary *dict = nil;
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"2453"] != nil)
dict = [[NSUserDefaults standardUserDefaults] dictionaryForKey:#"2453"];
if (dict) {
...
}
My hunch is that in this case dictionaryForKey is calling objectForKey behind the scenes and blindly trying to cast nil to NSDictionary for you, which would, I think, cause a crash. But by checking yourself first if there is any kind of object for that key, you can avoid the crash. Give it whirl and report back! :-)

[[NSUserDefaults standardUserDefaults] dictionaryForKey:#"2453"];
// ^^ ^
The "key" in -dictionaryForKey: must be an NSString. It cannot be an int. So although the key you supplied consists only of numbers, you still have to pass in a string using #"...". The fact that the key is absent is irrelevant to the crash.

if ([[NSUserDefaults standardUserDefaults] dictionaryForKey:#"2453"]) {
// this line will only be reached if there is something for #"2453"
}

Related

Saving incremental int variable

I need to save a variable that increments every time a user hits a button within the app. I've been trying to do that with NSUserDefaults with no success. Here's the code I'm using:
[[NSUserDefaults standardUserDefaults] setInteger:i++ forKey:#"AppCount"];
When I output this in the log, however, I keep getting 0.
Any help would be greatly appreciated.
Try adding:
[[NSUserDefaults standardUserDefaults] synchronize];
After each time you change the value of your integer.
Quoting Apple's documentation on synchronize:
Writes any modifications to the persistent domains to disk and updates
all unmodified persistent domains to what is on disk.
http://developer.apple.com/library/ios/DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/Reference/Reference.html#//apple_ref/occ/instm/NSUserDefaults/synchronize
So with this modification, your final code should look like this:
[[NSUserDefaults standardUserDefaults] setInteger:i++ forKey:#"AppCount"];
[[NSUserDefaults standardUserDefaults] synchronize];
EDIT: Actually on second thought, give this a try:
I think the problem is using i++ assumes that the application will always be able to keep track of the count, and every time you re-enter the application i gets reset.
The following works, I just tested it.
if (![[NSUserDefaults standardUserDefaults] integerForKey:#"AppCount"]) {
[[NSUserDefaults standardUserDefaults] setInteger:i forKey:#"AppCount"];
}else{
[[NSUserDefaults standardUserDefaults] setInteger:[[NSUserDefaults standardUserDefaults] integerForKey:#"AppCount"] + 1 forKey:#"AppCount"];
}
[[NSUserDefaults standardUserDefaults] synchronize];
You can use Static NSUIInteger appCount=0;
in the function user taps increase it value appCount++;
that keeps the value in function calls within the app. after app closing you write it to file.
- (void)viewDidLoad {
[super viewDidLoad];
countFirst= [[NSUserDefaults standardUserDefaults]integerForKey:#"Counter"];
countFirst++;
}
Write this wherever you want to increment.
[[NSUserDefaults standardUserDefaults] setInteger:countFirst++ forKey:#"Counter"];

Storing preferences in NSUser Defaults to recall later

Been working on some code streamlining and have realised that it would be really helpful if my app had a preferences system.
Now here's how my code works.
A method runs based upon an integer stored in NSUserDefaults
e.g.
if ([[NSUserDefaults standardUserDefaults] integerForKey:#"scifi1"] == 040){
[self spaceDown];
}
else if ([[NSUserDefaults standardUserDefaults] integerForKey:#"scifi1"] == 10040){
[self ctrldown];
[self spaceDown];
}
Now what I want to do is when I exit the view (via a specific button) is to dump the value of #"scifi1" into a new preference, say for example - an integer named #"savedscifi1"
Now I know how to save integers into NSUserDefaults,
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setInteger:VALUEHERE forKey:#"savedscifi1"];
[userDefaults synchronize];
However - I'm not sure how I can substiture in the value of scifi1 instead of (in this case) 'VALUEHERE' - can anyone help with this? I feel it's really simple but I can't help but think I'm being a bit thick...sleep deprived and approaching a deadline! I know I can't just call up #"scifi1"but beyond that....??
NSInteger value = [[NSUserDefaults standardUserDefaults] integerForKey: ...];
[[NSUserDefaults standardUserDefaults] setInteger: value forKey: ...];

how to check nsuserdefaults is empty or not

i am getting a list of items from sqlite database and place them in an array.
i need to get this array first time my app runs.
for this i am saving this array into NSuserdafaults.
my code is like this
if ([[NSUserDefaults standardUserDefaults] arrayForKey:#"categories"]) {
[[NSUserDefaults standardUserDefaults] setObject:appdelegate.categoriesList forKey:#"categories"];
NSLog(#"categorylist>>>>>> %#",appdelegate.categoriesList);
}
categoriesArray = [[NSMutableArray alloc]init];
categoriesArray = [[[NSUserDefaults standardUserDefaults] arrayForKey:#"categories"] mutableCopy];
then it not entered into if condition.
and if i try with not equal like this.
if (![[NSUserDefaults standardUserDefaults] arrayForKey:#"categories"]) {
[[NSUserDefaults standardUserDefaults] setObject:appdelegate.categoriesList forKey:#"categories"];
NSLog(#"categorylist>>>>>> %#",appdelegate.categoriesList);
}
categoriesArray = [[NSMutableArray alloc]init];
categoriesArray = [[[NSUserDefaults standardUserDefaults] arrayForKey:#"categories"] mutableCopy];
then enter for every build and run.
But i need this for first build and run i mean at installing time.
can any one please help me.
Thank u in advance.
(let me add comment if any one did n't understand my question)
categoriesArray = [[NSMutableArray alloc]init];
categoriesArray = [[[NSUserDefaults standardUserDefaults] arrayForKey:#"categories"] mutableCopy];
The lines above create a leak: you first allocate one array, and then you immediately assign a different array to the same pointer that was keeping track of the array that you allocated. After the second line, you have no way to release the first array.
As for the main question, I suspect that the check
if (![[NSUserDefaults standardUserDefaults] arrayForKey:#"categories"]) {
succeeds every time because there's never a value written for the key #"categories". I see that the lines inside that conditional block try to write a value, but appdelegate.categoriesList may well be nil.

Can you see the values of NSUserDefaults anywhere in the xcode debugger?

Can you see the values of NSUserDefaults naywhere in the xcode debugger?
Just wondering if this is possible?
Thanks,
Nick
I don't have a solution to view them in the debugger, but I can offer this:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSLog(#"%#", [defaults dictionaryRepresentation]);
For some caveman-debugging:)
EDIT: As David suggest in the comment, we can now do this in the debugging console:
po [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]
Swift 3.0
po UserDefaults.standard.dictionaryRepresentation()
I haven't done it but you should be able to execute a po (print object) command on the user defaults like so:
po [[NSUserDefaults standardUserDefaults] valueForKey:#"someKeyName"]
I prefer to wrap my defaults in a custom class and create a description method that dumps the defaults.
You can use the "defaults" command line utility to examine the defaults exactly. Read the man page for details.
Not aware of any GUI that displays NSUserDefaults, but I use this in my application delegate to see the settings at start up:
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSLog(#"%# DEFAULTS = %#", [self class], [defaults persistentDomainForName:[[NSBundle mainBundle] bundleIdentifier]]);
}
You can log or either use PO command at debugger
for Keys :
NSLog(#"%#", [[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys]);
or for Keys and values:
NSLog(#"%#", [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]);
& on debugger use:
getting all keys :
po [[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys]
for key & values :
po [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]
Updated for Swift 5
Print all UserDefault key-value pairs to console:
print(UserDefaults.standard.dictionaryRepresentation())
Print UserDefault keys to console:
print(UserDefaults.standard.dictionaryRepresentation().keys)
Print UserDefault values to console:
print(UserDefaults.standard.dictionaryRepresentation().values)
read:
po UserDefaults.standard.value(forKey: "key")
write:
po UserDefaults.standard.set(true, forKey: "key")
you can also add an expression directly on the Variable breakpoint view and adding : UserDefaults.standard.dictionaryRepresentation() see the image below .
add breakpoint view

Cannot read values from [NSUserDefaults standardUserDefaults] after synchronize

In the Application Delegate didFinishLaunching method, I am using the following code to build up a new NSDictionary to be used as the new settings bundle for the user:
NSNumber *testValue = (NSNumber*)[[NSUserDefaults standardUserDefaults] objectForKey:#"settingsversion"];
if (testValue == nil)
{
NSNumber *numNewDB = [NSNumber numberWithBool:NO];
NSNumber *numFirstUse = [NSNumber numberWithBool:YES];
NSDate *dateLastStatic = [NSDate date];
NSDate *dateLastMobile = [NSDate date];
NSNumber *numSettingsversion = [NSNumber numberWithFloat:1.0];
NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
numNewDB, #"newdb",
numFirstUse, #"firstuse",
numSettingsversion, #"settingsversion",
dateLastStatic, #"laststaticupdate",
dateLastMobile, #"lastmobileupdate",
nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults];
[[NSUserDefaults standardUserDefaults] synchronize];
}
Later in another ViewController I am trying to read back a value from that same Dictionary, saved as the NSUserDefaults - well at least I thought it would, but I don't get any valid object pointer for the desired member lastUpdate back there:
in .h file:
NSDate *lastUpdate;
in the .m file in a member function:
lastUpdate = (NSDate *)[[NSUserDefaults standardUserDefaults] objectForKey:#"laststaticupdate"];
Even, if I print out the content of [NSUserDefaults standardUserDefaults] I only get this:
2010-04-29 15:13:22.322 myApp[4136:207] Content of UserDefaults: <NSUserDefaults: 0x11d340>
This leads me to the conclusion that there is no standardUserDefaults dictionary somewhere in memory or it cannot be determined as such a structure.
Edit: Every time, I restart the app ión the device, the check for testValue is Nil and I am building up the dictionary again but after one run it should be persistent on the Phone, right?
Am I doing something wrong somewhere in between? I have the feeling that I yet didn't really understand how to load and save settings persistent for a certain application on the iPhone.
Is there anything I have to do additionally to this? Integrating a settings.bundle in XCode or saving the dictionary manually to the Documents folder?
Can someone help me out here? Thanks a lot!
registerDefaults doesn't actually write anything to disk. It just creates a 'defaults defaults' dictionary in memory. So everytime you restart the app, testValue should be nil.
If you want to set persistent values, use setObject:forKey:.
I don't know why you aren't getting a valid object back however.