This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Multivalue type settings bundle fields alway return null
I have a settings bundle in my iOS app which generates the following table in the settings app
In my app I attempt to generate the same table using NSUserDefaults and end up with this
My code to retrieve the values goes is:
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
ds->use_cache = [userDefaults boolForKey:#"use_cache"];
ds->high_bitrate = [userDefaults boolForKey:#"high_bitrate"];
and
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
[[cell detailTextLabel] setText:[defaults stringForKey:#"version"]];
The stringForKey with the key "version" always returns a null value. I can't seem to get my app to recognise the default parameters I have defined in the settings bundle.
Here is my settings bundle
The default values for the settings should be set using the registerDefaults: method. This sets up an NSRegistrationDomain from which they will be available. An example for this is below. Thanks to jrturton & Matthias Bauch for pointing out the problem with my first answer that was previously referring to http://greghaygood.com/2009/03/09/updating-nsuserdefaults-from-settingsbundle.
NSDictionary *appDefaults = [ NSDictionary
dictionaryWithObject:#"default_version_value" forKey:#"version" ];
[ [ NSUserDefaults standardUserDefaults ] registerDefaults:appDefaults ];
NSUserDefaults *userDefaults = [ NSUserDefaults standardUserDefaults ];
Also note these default values need to be set every time the application starts as stated in the documentation for registerDefaults:.
The contents of the registration domain are not written to disk; you need to call this method each time your application starts. You can place a plist file in the application's Resources directory and call registerDefaults: with the contents that you read in from that file.
Related
I have an App with a today extension. I created already an app group in the developer portal and created the target in my xcode project, linking the group in the capabilities for my app and today target.
So at the app side I'm saving my values like this:
NSUserDefaults *prefs = [[NSUserDefaults alloc] initWithSuiteName:suite];
[prefs setObject:value forKey:key];
[prefs synchronize];
The suite property is the name of my group created in the developer portal. Value is a NSDictionary.
NSDictionary* savedDict = [prefs objectForKey:key];
Calling this gives me the correct values
At the Extension Side I'm using swift and trying to get my UserDefaults like this
let userDefaults = UserDefaults.init(suiteName: "group.cryptochange.favorites")
let savedDict = userDefaults?.dictionary(forKey: "Favorites");
The problem is, that savedDict is nil.
When I print out all keys in my user defaults I see the "Favorites" key at the app side but if I'm printing out the keys in the extension, this key is missing.
Does anybody know where or what the problem could be?
Thanks in advance
EDIT 1:
I just recognize that it works with a debug build but not when I change the scheme to release
EDIT 2:
I just checked the documents directory of my app and see my app groups file which includes the values I saved.
When I look up at the documents dir of the extension there is no such a file. Is this works as intended?
After I set an "test" value inside my extension code the file appears with the test value
You have to make sure:
suite = "group.cryptochange.favorites"
key = "Favorites"
You have to check Extension is a member of group app
You should review that "Cast type" is correct
I hope my answers are useful
I have a general question when it comes to replacing an old application with a brand new one. The old application is several years old and written in Objective-C and I am developing an update from scratch in Swift.
I am wondering how to preserve a variable from the old app called "email_preference" which is stored in NSUserDefaults. How do I access the variable when the update is complete, and how do I test that I get the variable correctly (I feel like I have to do it correctly the first time or the value will be lost)?
These are the mentions I have found in the old code:
//Saves the email
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:self.email.text forKey:#"email_preference"];
//Gets the email
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *email = [defaults objectForKey:#"email_prefe
Thank you.
If the "new" app has the same bundle identifier as the "old" one, you can get the saved email just like this:
let email = UserDefaults.standard.object(forKey: "email_preference")
How to make some config file to my program so program can load settings from it befoce starting?
Thanks a lot!
It sounds like what you are interested in is some kind of user preferences, yes?
use NSUserDefaults class for application configuration. To establish the initial set of values before user customization make a plist file with the appropriate keys and values corresponding to what you wish to use in your application.
example of registering your default settings file with the system:
// Load default defaults.
// Defaults need to be registered prior to interface loading.
NSString* defaultsPath = [[NSBundle mainBundle] pathForResource:#"defaults" ofType:#"plist"];
NSDictionary* defaultDict = [NSDictionary dictionaryWithContentsOfFile:defaultsPath];
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
[defaults registerDefaults:defaultDict];
then in your application logic you can simply ask the NSUserDefaults object for a value (any of the plist supported types) for a given key using the various methods of NSUserDefaults:
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
BOOL myBool = [defaults boolForKey:#"myBool"];
// you can also get strings, data, numbers, dates, arrays, and dictionaries
I add a dictionary to NSUserDefaults and call 'synchronize' method,but when I close my app and reopen it the values which are saved in NSUserDefault are nil.
#define kStartTime #"startTime"
#define kEndTime #"endTime"
NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
NSString *startTime=#"08:00";
NSString *endTime=#"18:00";
NSDictionary *dict=[[NSDictionary alloc] initWithObjectsAndKeys:startTime,kStartTime,
endTime,kEndTime,
nil];
[defaults registerDefaults:dict];
[defaults synchronize];
And in the viewDidLoad method I call this:
NSString *startTimeValue=[defaults stringForKey:kStartTime];
the startTimeValue is still nil When I reopen my app in simulator.Is UserDefaults can't save in Simulator???
My point is when i close my app and reopen it in simulator the values are gone.
After I searched the apple document ,I got this.
registerDefaults:.
As is said in Apple Document :Adds the contents of the specified dictionary to the registration domain.
*The contents of the registration domain are not written to disk;*you need to call this method each time your application starts.You can place a plist file in the application's Resources directory and call registerDefaults: with the contents that you read in from that file.
So the function of the registerDefaults: is setting Default values in app,The Default value will not stored in disk by synchronize
I think you try to read the value from NSUserDefaults before you have registered the defaults.
If you register defaults these values are not saved to disk, they will not persist to the next application launch. You have to register the default values every time you launch the app.
When you read an object from NSUserDefaults and you have not saved a value before, the registered default value will be returned. If you have saved a value before, this value will be returned.
In the code you posted you have not saved anything to userDefaults. So the value you have registered as default will be returned. If you haven't registered any values this will return nil.
The code that registers the defaults should be put in a method that runs very early in the application life cycle. I would recommend to use application:didFinishLaunchingWithOptions:
If you want to save multiple values to NSUserDefaults you have to use multiple setObject:forKey: calls.
registerDefaults: can not be used to save multiple keys to NSUserDefaults at the same time!
NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
NSDictionary *dict=[[NSDictionary alloc] initWithObjectsAndKeys:startTime,#"kStartTime",
endTime,#"kEndTime",
nil];
[defaults registerDefaults:dict];
[defaults synchronize];
NSString *startTimeValue=[defaults stringForKey:#"kStartTime"];
NSLog(#"%#",startTimeValue);
you need to add keys like #"value" like this.
Now try this code....
I have seen some guides that say to do this, and others that say setting initial values and keys of NSUserDefaults this way will cause problems when an app is updated. I'm hoping I can definitively answer that here. In my appdelegate didFinishLaunchingWithOptions method I have:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (![defaults integerForKey:#"totalDays"]) {
// if there is no value for the key, set it to 1
[defaults setInteger:0 forKey:#"totalDays"];
}
if (![defaults objectForKey:#"currentDate"]) {
[defaults setObject:#"32 01" forKey:#"currentDate"];
}
if (! [defaults boolForKey:#"marked"]) {
[defaults setBool:NO forKey:#"marked"];
}
if (![defaults arrayForKey:#"checkedrows"]) {
NSMutableArray *arr1 = [NSMutableArray arrayWithArray:[defaults arrayForKey:#"checkedrows"]];
}
[defaults synchronize];
It might also be helpful to note, you don't "need" default values in there to use them. It might save you time from having to check them for null or zero values later in the app.
As the other answer stated, once values are saved to user defaults, it should persist from update to update and backup to backup. I've been using them for years with no issues with lost or corrupted data.
The data stored in the user defaults are save if the user updates the app. You will not get any problems with your code after an update.
You should not set the default values at all! Instead, use the handy method NSUserDefaults provides for exactly this purpose: -registerDefaults:. Call it early in your program's startup with a dictionary of the default values.
The advantage of this is that because -registerDefaults: is transient, you can tell the difference between "the user hasn't customized this preference" and "the user explicitly set this preference to the default value", which is important if you change default settings in a newer version of the program. It's also a little faster due to not needing to save to the disk.