Home > Articles > Programming > C/C++

iPhone/iPad Programming with C# and .NET: Loading Default User Settings in MonoTouch

📄 Contents

  1. Where Did My Defaults Go?!
  2. Code Analysis
  • Print
  • + Share This
Do your iPhone apps utilize the Settings application to provide users with default values? That's a great feature, but it's not useful unless it actually works! Bryan Costanich, using MonoTouch, shows how to get past the failure of the iPhone OS to preload your application defaults.
Like this article? We recommend

Where Did My Defaults Go?!

The iPhone operating system provides built-in support for allowing your application users to edit settings in your application via the Settings application (see Figure 1). This is all well and good; however, one very important thing to know about user settings is that the iPhone OS won't actually load your default settings until you access those settings from the Settings application. So even though you specify DefaultValue keys, they'll actually be null the first time your application runs!

To get around this problem, you need to initialize your defaults before accessing them. One of the easiest places to do this is in your AppDelegate constructor, because it runs when your application starts, before any user settings are likely to be used.

Figure 1 Custom application settings.

You can use the following helper class to load your app settings directly from your settings file:

public static class UserDefaultsHelper
{
      //========================================================================
      /// <summary>
      /// Loads the default settings from the Settings.bundle/Root.plist file. Also
      /// calls nested settings (referred to in child pane items) recursively, to
      /// load those defaults.
      /// </summary>
      //---- check to see if they've already been loaded for the first time
      if (!NSUserDefaults.StandardUserDefaults.BoolForKey ("__DefaultsLoaded"))
      {
            #if DEBUG
            Console.WriteLine ("Loading settings file for the first time");
            #endif

            string rootSettingsFilePath = NSBundle.MainBundle.BundlePath + "/Settings.bundle/Root.plist";

            //---- check to see if there is even a settings file
            if (System.IO.File.Exists (rootSettingsFilePath))
            {
                  //---- load the settings
                  NSDictionary settings = NSDictionary.FromFile (rootSettingsFilePath);
                  LoadSettingsFile (settings);
            }

            //---- mark them as loaded so this doesn't run again
            NSUserDefaults.StandardUserDefaults.SetBool (true, "__DefaultsLoaded");
      }
      //========================================================================

      //========================================================================
      /// <summary>
      /// Recursive version of LoadDefaultSettings
      /// </summary>
      private static void LoadSettingsFile (NSDictionary settings)
      {
            //---- declare vars
            bool foundTypeKey;
            bool foundDefaultValue;
            string prefKeyName;
            NSObject prefDefaultValue;
            NSObject key;

            //---- get the preference specifiers node
            NSArray prefs = settings.ObjectForKey (new NSString ("PreferenceSpecifiers")) as NSArray;

            //---- loop through the settings
            for (uint i = 0; i < prefs.Count; i++)
            {
                  //---- reset for each setting
                  foundTypeKey = false;
                  foundDefaultValue = false;
                  prefKeyName = string.Empty;
                  prefDefaultValue = new NSObject ();

                  //----
                  NSDictionary pref = new NSDictionary (prefs.ValueAt (i));

                  #if DEBUG
                  Console.WriteLine ("=============");
                  #endif

                  //---- loop through the dictionary of any particular setting
                  for (uint keyCount = 0; keyCount < pref.Keys.Length; keyCount++)
                  {
                        //---- shortcut reference
                        key = pref.Keys[keyCount];

                        //---- get the key name and default value
                        if (key.ToString () == "Key")
                        {
                              foundTypeKey = true;
                              prefKeyName = pref[key].ToString ();
                        }
                        else if (key.ToString () == "DefaultValue")
                        {
                              foundDefaultValue = true;
                              prefDefaultValue = pref[key];
                        }
                        else if (key.ToString () == "File")
                        {

                              #if DEBUG
                              Console.WriteLine ("calling recursively");
                              Console.WriteLine ("<nested>");
                              #endif

                              NSDictionary nestedSettings = NSDictionary.FromFile (
                                    NSBundle.MainBundle.BundlePath + "/Settings.bundle/" +
                                      pref[key].ToString () + ".plist");
                              LoadSettingsFile (nestedSettings);

                              #if DEBUG
                              Console.WriteLine ("</nested>");
                              #endif
                        }


                        //---- if we've found both, set it in our user preferences
                        if (foundTypeKey && foundDefaultValue)
                        {
                              NSUserDefaults.StandardUserDefaults[prefKeyName] = prefDefaultValue;
                        }

                        #if DEBUG
                        //---- write to the console, our values
                        WriteKeyAndValueToOutput (pref, key);
                        #endif
                  }
            }
      }
      //========================================================================

      //========================================================================
      /// <summary>
      /// Writes out the key and value information to the console, useful for debugging,
      /// or understanding how the user preferences are stored.
      /// </summary>
      private static void WriteKeyAndValueToOutput (NSDictionary dict, NSObject key)
      {
            Console.Write (key.ToString () + ":");

            if (dict[key] is NSString)
            {
                  Console.WriteLine (dict[key].ToString ());
            }
            else
            {
                  switch (dict[key].GetType ().ToString ())
                  {
                        case "MonoTouch.Foundation.NSNumber":
                              Console.WriteLine ((dict[key] as NSNumber).FloatValue.ToString ());
                              break;
                        case "MonoTouch.Foundation.NSArray":
                              Console.WriteLine ("");
                              NSArray items = dict[key] as NSArray;

                              for (uint j = 0; j < items.Count; j++)
                              {
                                    Console.WriteLine ("\t" + NSString.FromHandle (items.ValueAt (j)).ToString ());
                              }
                              break;
                  }

            }
      }
      //========================================================================

}
  • + Share This
  • 🔖 Save To Your Account