NSUserDefaults not working right - iphone

Having some trouble with NSUserDefaults here.
Here's how I'm creating it:
NSString *theCity = #"Test City";
[[NSUserDefaults standardUserDefaults] setObject:theCity forKey:#"SavedCity"];
Here's how I'm trying to retrieve it:
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"SavedCity"])
{
NSLog(#"Key exists! %#",[[NSUserDefaults standardUserDefaults] objectForKey:#"SavedCity"]);
}
else {
NSLog(#"No city saved!");
}
The problem I have is that even if there IS a key for "SavedCity" (I check the pref file in the Simulator directory), it always displays "No city saved". Am I doing something wrong?
Thanks!

Two things you could try.
1) Try synchronizing the user defaults after settings the string. [[NSUserDefaults standardUserDefaults] synchronize]
2) Try retrieving the string using -stringForKey:

I ran into a similar problem myself recently. Here's what fixed it for me.
From the iOS Application Programming Guide:
It is recommended that you register any default preference values programmatically at launch time in addition to including them in your settings bundle property lists. For newly installed applications, default preference values from the application’s settings bundle are not set until the Settings application runs. This means that if the user runs your application before running Settings, the default values specified in your settings bundle will not be available. Setting such values programmatically at launch time ensures that your application always has appropriate values. To register default values programmatically, use the registerDefaults: method of the NSUserDefaults class.

What you should add is:
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"SavedCity"] != nil)
Because you want to check if you've saved something.

Related

Is there any way to identify that my app is executing first time on iphone?

I want to show a message of instructions when user first time use my application, but then never until he won't delete it and re-download,,,
one easy way is to save some value in sqlite3 database and match it,
but I want to use something else,,,,
You can do anything the other answerers suggested, or just check for a certain file (call it firstrun.txt) under app "Documents" directory to exist at startup.
If it doesn't exist, show the welcome message and create it, otherwise, do nothing. When the user updates the app, the "Documents" directory doesn't get emptied.
That's it.
I'd use NSUserDefaults:
if ([[NSUserDefaults standardUserDefaults] boolForKey:kHasRun] == NO) {
// do something
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:kHasRun];
}
you ca use sqlite or plist or [NSUserDefaults standardUserDefaults] for saving value.

Where to initialize iPhone application defaults

I just started using the preferences pane to let users customize some settings in my iOS app, and it was pretty easy to create the Settings.bundle and access the information from it. My problem is that I read in the Apple docs that the settings should be programatically initialized:
It is recommended that you register any default preference values programmatically at launch time in addition to including them in your settings bundle property lists. For newly installed applications, default preference values from the application’s settings bundle are not set until the Settings application runs. This means that if the user runs your application before running Settings, the default values specified in your settings bundle will not be available. Setting such values programmatically at launch time ensures that your application always has appropriate values. To register default values programmatically, use the registerDefaults: method of the NSUserDefaults class.
Where in the app is this initialization done, and how can I be sure that I'm not overwriting a user-supplied value? Is this handled in some method of the App Delegate?
You should register your defaults before you try to access a value stored in your NSUserDefaults.
You could do it in - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions.
Registering your defaults is fast, so there is no need to optimize this. Just do it at the launch of the app.
I store my userdefaults in a plist and register the content of this list, like this:
NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"DefaultUserDefaults" ofType:#"plist"]];
[[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];
If you register your defaults like this you don't have to worry that you overwrite user supplied values.
NSUserdefaults uses "domains" where it stores it's values. If you register your defaults they are stored in the registration domain. If a User stores a value those values are stored in the application domain.
If you try to get a value from NSUserdefaults it looks if the value is present in the application domain, and if it's not there it takes the value from the registration domain.
Edit:
you would access those values (or better, the values that are stored in your nsuserdefaults, and those as a fallback if there are no user provided values) like this:
NSInteger minutesToWait = [[NSUserDefaults standardUserDefaults] integerForKey:#"MinutesToWait";
NSString *urlString = [[NSUserDefaults standardUserDefaults] stringForKey:#"DefaultURLStr"];
The plist is just another representation of a NSDictionary with keys and values. The key is the same key you use to access the userdefaults, and the value is your defaultvalue.
Pretty straight forward.
It doesn't matter how you create the dictionary. You can do it in code as well.
As #fluchtpunkt suggested, you can register the defaults using:
NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"DefaultUserDefaults" ofType:#"plist"]];
[[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];
Personally, I check for each value independently in my App Delegate.
#define kSettings [NSUserDefaults]
if([kSettings boolForKey:#"firstRun"] == nil){
//
// Set up the initial settings...
//
[kSettings setBool:NO forKey:#"firstRun"];
}
I write a "reset" method and then call it on first run. I prefer doing this in code, but you theoretically could use a plist. I just feel like it's one less place to go wrong.
You can use the same method inside your app delegate that you use to setup your initial window, didFinishLaunchingWithOptions:
However, you may also need some logic inside applicationWillEnterForeground:, because potentially your user could put your app into the background, change settings inside the settings app, then resume your app and expect those changes to have been applied.
#MatthiasBauch or #Moshe's answers will most likely work for most people, but for anyone who like me had their settings in a Root.plist file (I was using the InAppSettingsKit), you have to dig a bit deeper into that particular plist file to get the actual default values of the settings (since they're not at the top level of the plist, but nested under the key PreferenceSpecifiers). Here is a link to another answer here, containing the extra code that worked for me:
https://stackoverflow.com/a/10497898/381233

Can Settings bundle use values from application's Info.plist file?

is it possible to use values from application's Info.plist file as DefaultValue value for items in Settings.bundle? For example CFBundleVersion. I've tried entering it as ${CFBundleVersion} but it didn't work. I've also tried changing DefaultValue type but with no success. Any ideas?
The reasons behind are simple:
CFBundleVersion is known at compile
time, so I won't have to take its
value from application's mainBundle
and then apply that value to
NSUserDefaults.
Other reason is that just after
installing the app, but before
running it, Settings bundle values
are not in-sync as the code setting
NSUserDefaults did not have a
chance to execute itself... so it would be
boring to always remember that I have
to change my Settings bundle values
manually.
This is how I synchronize my app's version to use in my Settings.bundle
[defaults setObject:[[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"] forKey:#"kVersion"];
[defaults synchronize];
I place that piece of code in my didFinishLaunchingWithOptions: app delegate, so every time the app launches it makes sure that the correct version is displayed in my Settings.bundle. This takes the app version value from your info.plist

Is there an easy way to change iPhone Application Settings from within an application?

I've got application settings working just fine. However, I'd like to be able to change my app settings from within my app.
It seems as though there should be some kind of generic way to add this functionality to my app without having to recreate all the controls myself. I mean, the code is already written in apple's settings app.
Maybe someone wrote this code and open sourced it? (if it is not already available)
I prefer my own Settings class as I don't like to write the same stuff again and again. Therefore I am using a method like ...
- (void) setValue:(id)value forKey:(NSString *)aKey {
[[NSUserDefaults standardUserDefaults] setObject:value forKey:aKey];
[[NSUserDefaults standardUserDefaults] synchronize];
}
and fetching would be ...
- (id) valueForKey:(NSString *)aKey {
return [[NSUserDefaults standardUserDefaults] valueForKey:aKey];
}
A lot of people have thought the same; file a bug with Apple, and maybe eventually they'll listen.
I believe you're looking for NSUserDefaults. The documentation is available here.

How to manually read from iPhone preferences?

I just wrote a few values to my user preferences using NSUserDefaults. Is there a way I can go in and examine the persisted preferences file manually (when running on the simulator) to make sure they were written properly?
See related: Easy way to see saved NSUserDefaults?
NSString *text = [[NSUserDefaults standardUserDefaults] stringForKey:#"ValueName"];
NSLog(#"%#",text);