11.2. Preference Bundles

In Chapter 10, you learned how to build a preferences table to allow users to change settings in real time. This is ideal for applications where exiting the application to change a setting can be problematic. For most applications, however, the global settings for an application can (and should) be changed from within the Settings application included with the iPhone. When you create a preference bundle, your application's icon will appear at the bottom of the Settings application, giving your users a centralized and standardized place to edit application settings.

Xcode provides a template for creating preferences bundles, and gives you enough content to get you started. To add a preferences bundle to your application, open your project in Xcode and select New File from the File menu. You'll be prompted to select a file type. Select the Settings category from the iPhone OS group, and select the Settings Bundle file. When prompted, name the file Settings.bundle and add it to your project. A sample bundle will be added to your application with an example text field, switch, and slider setting.

To edit the settings in your bundle, open the file named Root.plist. This will appear underneath the Settings.bundle folder that now exists on the sidebar of your project.

By default, the property list will be displayed in a property list editor, making it easy to add new key/value pairs with a few clicks. If you wish to work on the file's raw contents, right-click the file and select Plain Text File from the Open As menu. This will open the file in a text editor, where you can edit the raw XML. Since editing a property list in Xcode's property editor is effortless, we'll show you how it's done under the hood.

11.2.1. Adding Keys

Each entry in the preferences bundle is represented by a dictionary underneath the PreferenceSpecifiers section of the property list. Whichever items are defined in this array will be displayed to the user when editing your application's preferences. Each row in the array can define a new field or group separator for the preferences table that is displayed.

To add a new row, right-click the PreferenceSpecifiers array and select Add Row. A new row will be added to the top of the array. Right-click the new item and select Dictionary from the Value Type menu. This will change the item from a string entry field into a dictionary that you can use to define a new cell. Alternatively, you may select an existing item and copy it. Select the PreferenceSpecifiers array again, then paste. This will duplicate the row, giving you a template to work from.

11.2.1.1. Group separators

Group separators allow you to break your preferences table up into logical groups. To add a group separator, add a key to the dictionary named Type. Set the value for this key to PSGroupSpecifier. Create a second key named Title, whose value represents the name to display as the group label. Both rows should be of type String:

<array>
    <dict>
        <key>Type</key>
        <string>PSGroupSpecifier</string>
        <key>Title</key>
        <string>Main Settings</string>
    </dict>
</array>

11.2.1.2. Text fields

Text fields allow you to accept direct input from the user, such as a username or password. To add a text field, add the following keys to a new dictionary item within the PreferenceSpecifiers array. All key values are represented as strings unless otherwise specified:



Type

The type for a text field is PSTextFieldSpecifier.



Title

The title to display to the left of the field, for example, "Username."



Key

The name of the key to represent the actual value. This will be addressed in your code.



DefaultValue

The default value for the field. An empty value is acceptable here to indicate no value.



IsSecure

This is a Boolean field that you should set to true if the field is accepting secure text, such as a password. The correct syntax for declaring a Boolean field follows:

<key>IsSecure</key>
<true/>



KeyboardType

Defines the type of keyboard that should be raised when the user enters this field. Supported values include:

  • Alphabet

  • NumbersAndPunctuation

  • NumberPad

  • URL

  • EmailAddress



AutocapitalizationType

Allows you to define if and how the Settings application should autocapitalize the user's input into this field. Possible values include:

  • None

  • Word

  • Sentences

  • AllCharacters



AutoCorrectionType

Allows you to define if and how the Settings application should autocorrect text entered into this field. Possible values are Default, Yes, and No.

A complete text field might look like the following example:

<dict>
    <key>Type</key>
    <string>PSTextFieldSpecifier</string>
    <key>Title</key>
    <string>Username</string>
    <key>Key</key>
    <string>username_preference</string>
    <key>DefaultValue</key>
    <string></string>
    <key>IsSecure</key>
    <false/>
    <key>KeyboardType</key>
    <string>Alphabet</string>
    <key>AutocapitalizationType</key>
    <string>None</string>
    <key>AutocorrectionType</key>
    <string>No</string>
</dict>

11.2.1.3. Toggle switches

Toggle switch entries will render a UISwitch in the preferences pane, which the user can set On or Off. This is useful for adding Boolean preferences to activate or deactivate a given feature. To add a toggle switch field, add the following keys to a new dictionary item within the PreferenceSpecifiers array. All key values are represented as strings unless otherwise specified:



Type

The type for a switch field is PSToggleSwitchSpecifier.



Title

The title to display to the left of the field, for example, "Extra Lives."



Key

The name of the key to represent the actual value. This will be addressed in your code.



TrueValue

The value to set the Key field to when the switch is turned to the On position.



FalseValue

The value to set the Key field to when the switch is turned to the Off position.



DefaultValue

This Boolean value specifies the default position for the switch. This should be set to true to place the switch in the On position by default, or set to false to place the switch in the Off position by default. An example follows:

<key>DefaultValue</key>
<false/>

A complete switch entry might look like the example below:

<dict>
    <key>Type</key>
    <string>PSToggleSwitchSpecifier</string>
    <key>Title</key>
    <string>Extra Points</string>
    <key>Key</key>
    <string>extrapoints_preference</string>
    <key>DefaultValue</key>
    <false/>
    <key>TrueValue</key>
    <string>YES</string>
    <key>FalseValue</key>
    <string>NO</string>
</dict>

11.2.1.4. Sliders

Entries for sliders will draw a UISlider in the preferences table. Sliders allow the user to loosely specify a range of values, and are useful for visually accommodating difficulty in a game, sound volume, or other such value ranges. To add a slider field, add the following keys to a new dictionary item within the PreferenceSpecifiers array. All key values are represented as strings unless otherwise specified.

Sliders do not accommodate titles, so it's generally best to keep sliders in a separate group, using the group label as the title:



Type

The type for a multivalue field is PSMultiValueSpecifier.



Key

The name of the key to represent the actual value. This will be addressed in your code.



MinimumValue

A numeric field identifying the minimum value for the slider. You can define this as either an integer type field or a real type field, depending on whether you want values represented as integers or floating-point numbers. An example follows:

<key>MinimumValue</key>
<real>10.0</real>



MaximumValue

A numeric field identifying the minimum value for the slider. You can define this as either an integer type field or a real type field, depending on whether you want values represented as integers or floating-point numbers, and it should match the type used to set the MinimumValue field.



DefaultValue

A numeric field identifying the default value for the slider. You can define this as either an integer type field or a real type field, and does not need to match the value fields' types.



MinimumValueImage, MaximumValueImage

To display an image next to the minimum and/or maximum value ends of the slider, specify the filename of the image relative to the program folder.

A complete slider might look like the example below:

<dict>
    <key>Type</key>
    <string>PSSliderSpecifier</string>
    <key>Key</key>
    <string>musicvolume_preference</string>
    <key>DefaultValue</key>
    <real>5.0</real>
    <key>MinimumValue</key>
    <real>0.0</real>
    <key>MaximumValue</key>
    <real>10.0</real>
    <key>MinimumValueImage</key>
    <string>minvalue.png</string>
    <key>MaximumValueImage</key>
    <string>maxvalue.png</string>
</dict>

11.2.1.5. Multivalue fields

The equivalent to a drop-down menu in the Settings application is a multivalue field. Multivalue fields allow you to specify a number of different options, giving the user the option to choose one from the list. To add a multivalue field, add the following keys to a new dictionary item within the PreferenceSpecifiers array. All key values are represented as strings unless otherwise specified.

Sliders do not accommodate titles, so it's generally best to keep sliders in a separate group, using the group label as the title.



Type

The type for a slider field is PSSliderSpecifier.



Key

The name of the key to represent the actual value. This will be addressed in your code.



Title

The title to display to the left of the field, for example, "Difficulty."



Titles

An array of possible selections, as displayed to the user. An example follows:

<key>Titles</key>
            <array>
                <string>Easy</string>
                 <string>Medium</string>
                <string>Hard</string>
            </array>



Values

An array containing the actual values mapped to each title. These will be the values your application sees. An example follows. Each value is mapped to the titles displayed in the Titles array:

<key>Values</key>
            <array>
                <string>1</string>
                 <string>2</string>
                <string>3</string>
            </array>



DefaultValue

The value of the default selection. This should map to an element in the Values array.

A complete multivalue field might look like the example below:

<dict>
    <key>Type</key>
    <string>PSMultiValueSpecifier</string>
    <key>Title</key>
    <string>Difficulty</string>
    <key>Key</key>
    <string>difficulty_preference</string>
    <key>Values</key>
    <array>
        <string>1</string>
        <string>2</string>
        <string>3</string>
    </array>
    <key>Titles</key>
    <array>
        <string>Easy</string>
        <string>Medium</string>
        <string>Hard</string>
    </array>
    <key>DefaultValue</key>
    <string>2</string>
</dict>

                                          

11.2.1.6. Child panes

In addition to groups, preferences bundles allow you to specify additional child panes. When the user taps on the child pane, the Settings application will scroll to the new pane and present that pane's options. A Back button will be automatically presented to the user, allowing him to navigate back to your root pane.

To add a child pane, specify the following string fields:



Type

The type for a child pane is PSChildPaneSpecifier.



Key

A unique key for the child pane.



Title

The title of the child pane to display to the user. The child pane is presented as a button with a disclosure arrow.



File

The name of another property list within Settings.bundle containing the child pane you'd like to display. Leave off the .plist extension from the filename.

A complete child pane entry might look like the example below:

<dict>
    <key>Type</key>
    <string>PSChildPaneSpecifier</string>
    <key>Title</key>
    <string>Extended Preferences</string>
    <key>Key</key>
    <string>extended_preferences</string>
    <key>File</key>
    <string>Extended</string>
</dict>

11.2.2. Reading Preference Bundle Values

The preferences set from within your bundle are stored in a standard property list in your application sandbox's Library/Preferences folder. To load values individually, use the NSUserDefaults class to access property list settings:

NSString *difficulty = [ [ NSUserDefaults standardUserDefaults ]
    stringForKey:@"difficulty_preference" ];

Alternatively, you can load the property list containing all preferences directly into an NSDictionary object and work with it as you learned earlier in this chapter:

 

NSDictionary *settings = [ NSUserDefaults standardUserDefaults
    dictionaryRepresentation ];
NSLog(@"Difficulty: %@\n", [ settings valueForKey: @"difficulty_preference" ]);

                                          

11.2.3. Further Study

Now that you've learned about preference bundles, try these exercises:

  • Take the ShootStuffUp demo from Chapter 10 and convert it into a preferences bundle.

  • Check out the NSUserDefaults.h prototypes. You'll find these in /System/Library/Frameworks/Foundation.framework/Headers.