Code Analysis
The first method, LoadDefaultSettings, is the method you'll call from your AppDelegate to load the settings. The first part of this code simply checks whether we've ever loaded the defaults, and loads them only if we haven't already done so. (To perform the check, we look for a Boolean property, __DefaultsLoaded, that's stored in the settings.) If we don't perform this check, any changes in our settings will be overwritten by the defaults, which we don't want to happen. We also check whether the Root.plist file exists.
The other significant portion of this method is the following lines:
NSDictionary settings = NSDictionary.FromFile (rootSettingsFilePath); LoadSettingsFile (settings);
NSDictionary allows you to load a specially formatted dictionary from a file. In this case, it will accept a property list file (our Root.plist). In the first line, we load it by creating a path to the file from our BundlePath and then our Settings.bundle. NSBundle.MainBundle.BundlePath gives us the path of our application's bundle. Settings.bundle is the directory where we store our settings.
The second line of code calls the LoadSettingsFile. This is refactored out of this method because settings files can actually reference other settings files, so our LoadSettingsFile method will actually have to call itself recursively in order to load the referenced files.
In LoadSettingsFile, one of the first things we do is get an NSArray object from the PreferenceSpecifiers node:
NSArray prefs = settings.ObjectForKey (new NSString ("PreferenceSpecifiers")) as NSArray;
Next, we loop through each one of the settings groups:
for (uint i = 0; i < prefs.Count; i++)
Each preference is actually another dictionary of key/value pairs, so we loop through those as well:
for (uint keyCount = 0; keyCount < pref.Keys.Length; keyCount++)
If the preference has a "File" key, we need to load those settings as well, so we call the function recursively with that preference file:
else if (key.ToString () == "File") { NSDictionary nestedSettings = NSDictionary.FromFile ( NSBundle.MainBundle.BundlePath + "/Settings.bundle/" + pref[key].ToString () + ".plist"); LoadSettingsFile (nestedSettings); }
We also check to determine whether both a Key of type "Key" and a DefaultValue are present. If so, we set the default value of that setting in NSUserDefaults:
if (foundTypeKey && foundDefaultValue) { NSUserDefaults.StandardUserDefaults[prefKeyName] = prefDefaultValue; }
This line actually does our work of loading the defaults.
I've also added a method called WriteKeyAndValueToOutput that gets called if you're in Debug mode; it writes to the console the values and types of the keys to illustrate how they're stored.
This UserDefaultsHelper.LoadDefaultSettings method can be called from your AppDelegate constructor, as in the following example:
public AppDelegate () : base() { //---- set any user default values (they're not actually set until UserDefaultsHelper.LoadDefaultSettings (); //---- initialize our user settings, which loads them from the file (if they exist) NSUserDefaults.StandardUserDefaults.Init (); }
After you load your application defaults, you should also call the Init method on the StandardUserDefaults class, as shown in the following line:
NSUserDefaults.StandardUserDefaults.Init ();
This step loads any settings that have been saved. It's important to call it after your defaults have been loaded, so that any saved changes override the defaults.
When we run the attached code, any defaults we've specified should now show up in our application, as shown in Figure 2.
Figure 2 Sample application with the defaults loading correctly.
Congratulationsnow you know how to load user defaults automatically from your application!