iPhone Application Development : Reading and Writing User Defaults (part 2) - Implementing System Settings

7/6/2011 5:43:09 PM

Implementing System Settings

One option to consider for providing application preferences is to use the Settings application. You do this by creating and editing a settings bundle for your application in Xcode rather than by writing code and designing a UI, so this is a very fast and easy option.

For our second application of the hour, we’ll create ReturnMe, an application that tells someone who finds a lost device how to return it to its owner. The Settings application will be used to edit the contact information of the owner and to select a picture to evoke the finder’s sympathy.

Setting Up the Project

As we frequently do, begin by creating a new View-based iPhone application in Xcode called ReturnMe.

We want to provide the finder of the lost device with a sympathy-invoking picture and the owner’s name, email address, and phone number. Each of these items will be configurable as an application preference, so we’ll need outlets to set the values of a UIImageView and three UILabels.

Open the ReturnMeViewController.h file in the Classes group and add outlets and properties for each control. The completed ReturnMeViewController.h file should look like Listing 5.

Listing 5.
#import <UIKit/UIKit.h>

@interface ReturnMeViewController : UIViewController {
IBOutlet UIImageView *picture;
IBOutlet UILabel *name;
IBOutlet UILabel *email;
IBOutlet UILabel *phone;

@property (nonatomic, retain) UIImageView *picture;
@property (nonatomic, retain) UILabel *name;
@property (nonatomic, retain) UILabel *email;
@property (nonatomic, retain) UILabel *phone;


After updating the interface file, add corresponding @synthesize lines within the ReturnMeViewController.m file for each property:

@synthesize picture;
@synthesize name;
@synthesize email;
@synthesize phone;

And, of course, release all these objects in the dealloc method:

- (void)dealloc {
[picture release];
[name release];
[email release];
[phone release];
[super dealloc];

We want a few images that will help goad our Good Samaritan into returning the lost device rather than selling it to Gizmodo. Drag the dog1.png, dog2.png, and coral.png files from the project’s Images folder into the Resources group. When you drag the images into Xcode, make sure you click the option to copy them into the destination group’s folder so that copies of the images will be placed in your Xcode project’s directory.

Remember, to support the higher resolution display of the iPhone 4, all you need to do is create images with twice the horizontal and vertical resolution as your standard iPhone image resources, include a @2x suffix on the filename, and add them to your project. The developer tools and iOS take care of the rest!

Creating the Interface

Now let’s lay out the ReturnMe application’s UI. Open Interface Builder by double-clicking the ReturnMeViewController.xib file in the Resources group:

Open the XIB file’s view.

Drag three UILabels onto the view. Click each label and open the Attributes Inspector (Command+1), and set the text to a default value of your choosing for name, email, and phone number.

Drag a UIImageView to the view. Size the image view to take up the majority of the iPhone’s display area.

With the image view selected, open the Attributes Inspector (Command+1). Set the mode to be Aspect Fill, and pick one of the animal images you added to the Xcode project from the Image drop-down.

Add some additional UILabels to explain the purpose of the application and labels that explain each preference value (name, email, and phone number).

As long as you have the three labels and the image view in your UI, as seen in Figure 5, you can design the rest as you see fit. Have fun with it!

Figure 5. Create an interface with an image, labels, and anything else you’d like!

When you’re finished building the interface, connect the UIImageView and three UILabels to their corresponding outlets—picture, name, email, and phone. There aren’t any actions to connect, so just Control-drag from the File’s Owner icon to each of these interface items, choosing the appropriate outlet when prompted.

Now that the interface is built, we’ll create the Settings Bundle, which will enable us to integrate with the iPhone’s Settings application.

Creating the Settings Bundle

Create a new settings bundle in Xcode by selecting File, New File from the menu and selecting Settings Bundle from the iOS Resource group in the sidebar, as shown in Figure 6.

Figure 6. Settings bundle in Xcode’s New File dialog.

Keep the default name of Settings.bundle when you create it. Drag the newly created settings bundle into the Resources group if it does not get created there.

The file that controls how our ReturnMe application will appear in the Settings application is the Root.plist file in the settings bundle. We can edit this file with the Property List Editor that is built in to Xcode. We will add preference types to it (see Table 1) that will be read and interpreted by the Settings application to provide the UI to set our application’s preferences.

Table 1. Preference Types
Text fieldPSTextFieldSpecifierEditable text string
Toggle switchPSToggleSwitchSpecifierOn/off toggle button
SliderPSSliderSpecifierSlider across a range of values
MultivaluePSMultiValueSpecifierDrop-down value picker
TitlePSTitleValueSpecifierRead-only text string
GroupPSGroupSpecifierTitle for a logical group of preferences
Child panePSChildPaneSpecifierChild preferences page

The ReturnMe preferences will be grouped into three groups: Sympathy Image, Contact Information, and About. The Sympathy Image group will contain a multivalue preference to pick one of the images, the Contact Information group will contain three text fields, and the About group will link to a child page with three read-only titles.

Expand the Settings.bundle in Xcode and click the Root.plist file. You’ll see a table of three columns: Key, Type, and Value. Expand the PreferencesSpecifiers property in the table, and you’ll see a series of four dictionary properties. These are provided by Xcode as samples, and each of them will be interpreted by Settings as a preference. You will follow the simple schema in the Settings Application Schema Reference in the iOS Reference Library to set all the required properties, and some of the optional properties, of each preference.

Expand the first dictionary property under PreferenceSpecifiers called Item 0, and you’ll see that its Type is PSGroupSpecifier. This is the correct Type to define a preference group, but change the Title property’s value to Sympathy Image by clicking it and typing the new title. Expand the second item (Item 1) and you’ll see that its Type is PSTextFieldSpecifier. Our Sympathy Image will be selected as a multivalue, not a text field, so change the Type to PSMultiValueSpecifier. Change the Title to Image Name, the Key to picture, and the DefaultValue to Dog. The remaining four keys under Item 1 apply to text fields only, so delete them by selecting them and pressing the Delete key.

The values for a multivalue picker come from two arrays, an array of item names and an array of item values. In our case, the name and value arrays will be the same, but we still must provide both of them. To add another property under DefaultValue, click the plus sign at the end of the row (see Figure 7) to add another property at the same level.

Figure 7. Add another property in Xcode’s Property List Editor.

The new item will have the default name of New Item, so change that to Values. The Type column defaults to String, so change it to Array. Each of the three possible image names needs a property under the Values property. Expand the Values item’s disclosure triangle, and notice that the plus sign at the end of the row changes to an icon with three lines (see Figure 8). This icon adds child properties, rather than properties at the same level. Click the icon three times to add properties that’ll be called Item 0, Item 1, and Item 2.

Figure 8. Add child items in Xcode’s Property List Editor.

Change the Value of the three new child properties to Dog, Mean Dog, and Coral. Repeat this step to add a peer of Values called Titles. Titles is also an Array type and has the same three String type children with the same values, as shown in Figure 9.

Figure 9. The completed image selector preference in Xcode’s Property List Editor.

The third property (Item 2) in our plist PreferenceSpecifiers should be a PSGroupSpecifier with a title of Contact Information. Change the Type and Title of Item 2 and remove the extra items.

The fourth property (Item 3) is the name preference. Change the Type to PSTextFieldSpecifier, the Key to name, and the DefaultValue to Your Name with a Type of String. Add three more keys to Item 3. These should be String types and are optional parameters that set up the keyboard for text entry. Set the keys to KeyboardType, AutocapitalizationType, and AutocorrectionType, and the values to Alphabet, Words, and No, respectively.

You can test your settings so far by saving the plist, building and running the ReadMe application in the iPhone Simulator, exiting the application with the Home button, and then running the Settings application in the simulator. You should see a Settings selection for the ReturnMe application and settings for the Sympathy Image and Name.

Add two more PSTextFieldSpecifier preferences to the plist; mirror what you set up for the Name preference: one for email and one for phone number. Use the keys of email and phone, and change the KeyboardType to EmailAddress and NumberPad, respectively.

The final preference is About, and it opens a child preference pane—we’ll add two more items to accomplish this. First, add a new item—Item 6—to the plist. Configure the item as a dictionary; then add a Type of PSGroupSpecifier and a Title of About ReturnMe.

Next, add Item 7, configured as a dictionary. Expand the new item and set a property with a Type of PSChildPaneSpecifier, a Title of About, and a String property with a Key of File and a Value of About. The child pane element assumes the value of File exists as another plist in the settings bundle. In our case, this is a file called About.plist.

The easiest way to create this second plist file in the settings bundle is by copying the Root.plist file we already have. Right-click the Root.plist file in Xcode, and select the Open with Finder menu option. This opens the plist in the external Property List Editor. Select File, Save As and change the name to About.plist before clicking Save. Xcode won’t immediately notice that your settings bundle has a new plist file. Collapse and expand Settings.bundle to refresh the contents.

Edit About.plist to have one group property titled About ReturnMe and three PSTitleSpecifier properties for Version, Copyright, and Website. PSTitleSpecifierDefaultValue. If you have any difficulties setting up your plist files, compare your properties have four properties: Type, Title, Key, and preferences UI to Figure 10 and your plists to the plists in the settings bundle in the project’s source code to see where you might have made a misstep.

Figure 10. ReturnMe’s settings in the Settings application.

Connecting Preferences to the Application

We have four preferences we want to retrieve from the preferences database: the selected image and the device owner’s name, email, and alternative phone number. Add a key constant for each of these to the top of the ReturnMeViewController.h file in Xcode:

#define kName @"name"
#define kEmail @"email"
#define kPhone @"phone"
#define kReward @"reward"
#define kPicture @"picture"

We have now bundled up our preferences so that they can be set by the Settings application, but our ReturnMe application also has to be modified to use the preferences. We do this in the ReturnMeViewController.m file’s viewDidLoad event. Here we will call a helper method we write called setValuesFromPreferences. Our code to use the preference values with the NSserDefaults API looks no different from the Flashlight application. It doesn’t matter if our application wrote the preference values or if the Settings application did; we can simply treat NSUserDefaults like a dictionary and ask for objects by their key.

We provided default values in the settings bundle, but it’s possible the user just installed ReturnMe and has not run the Settings application. We should provide the same default settings programmatically to cover this case, and we can do that by providing a dictionary of default preference keys and values to the NSUserDefaults registerDefaults method. Add the methods in Listing 6 to the ReturnMeViewController.m file.

Listing 6.
- (NSDictionary *)initialDefaults {
NSArray *keys = [[[NSArray alloc] initWithObjects:
kPicture, kName, kEmail, kPhone, nil] autorelease];
NSArray *values = [[[NSArray alloc] initWithObjects:
@"Dog", @"Your Name", @"",
@"(555)555-1212", nil] autorelease];
return [[[NSDictionary alloc] initWithObjects: values
forKeys: keys] autorelease];

-(void)setValuesFromPreferences {

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults registerDefaults: [self initialDefaults]];
NSString *picturePreference = [userDefaults stringForKey:kPicture];
if ([picturePreference isEqualToString:@"Dog"]) {
picture.image = [UIImage imageNamed:@"dog1.png"];
} else if ([picturePreference isEqualToString:@"Mean Dog"]) {
picture.image = [UIImage imageNamed:@"dog2.png"];
} else {
picture.image = [UIImage imageNamed:@"coral.png"];

name.text = [userDefaults stringForKey:kName];
email.text = [userDefaults stringForKey:kEmail];
phone.text = [userDefaults stringForKey:kPhone];


With this supporting code in place, we have the ability to set some default preferences, and load preferences that are configured in the iPhone Settings application. That said, we still need to load the preferences when the application starts. Edit ReturnMeViewController.m, implementing the viewDidLoad method to invoke setValuesFromPreferences:

- (void)viewDidLoad {
[self setValuesFromPreferences];
[super viewDidLoad];

Build and run the modified ReturnMe application and switch back and forth between the Settings and ReturnMe applications. You can see that with very little code on our part we were able to provide a sophisticated interface to configure our application. The Settings application’s plist schema provides a fairly complete way to describe the preference needs of our application.

  •  - Mobile Application Security : SMS Security - Overview of Short Message Service
  •  - Mobile Application Security : Bluetooth Security - Bluetooth Security Features
  •  Integrating Your Application with Windows Phone 7
  •  Introducing Windows Phone 7 Photo Features (part 2) - Using a Chooser to Open Photos & Saving Photos to the Phone
  •  Introducing Windows Phone 7 Photo Features (part 1) - Using a Chooser to Take Photos
  •  Mobile Application Security : Bluetooth Security - Bluetooth Technical Architecture
  •  Mobile Application Security : Bluetooth Security - Overview of the Technology
  •  Windows Phone 7 Development : Push Notifications - Implementing Cloud Service to Track Push Notifications
  •  Windows Phone 7 Development : Push Notifications - Implementing Raw Notifications
  •  Windows Phone 7 Development : Push Notifications - Implementing Tile Notifications
  •  Windows Phone 7 Development : Push Notifications - Implementing Toast Notifications
  •  iPhone Application Development : Creating a Navigation-Based Application
  •  Windows Phone 7 Development : Push Notifications - Introducing the Push Notifications Architecture
  •  Windows Phone 7 Development : Push Notifications - Understanding Push Notifications
  •  Windows Phone 7 Development : Handling Multiple Concurrent Requests with Rx.NET
  •  WAP and Mobile HTML Security : Application Attacks on Mobile HTML Sites
  •  WAP and Mobile HTML Security : Authentication on WAP/Mobile HTML Sites & Encryption
  •  iPhone Application Development : Displaying and Navigating Data Using Table Views - Building a Simple Table View Application
  •  iPhone Application Development : Understanding Table Views and Navigation Controllers
  •  Windows Phone 7 Development : Revising WeatherRx to Manage Slow Data Connections
    Top 10
    Nikon 1 J2 With Stylish Design And Dependable Image And Video Quality
    Canon Powershot D20 - Super-Durable Waterproof Camera
    Fujifilm Finepix F800EXR – Another Excellent EXR
    Sony NEX-6 – The Best Compact Camera
    Teufel Cubycon 2 – An Excellent All-In-One For Films
    Dell S2740L - A Beautifully Crafted 27-inch IPS Monitor
    Philips 55PFL6007T With Fantastic Picture Quality
    Philips Gioco 278G4 – An Excellent 27-inch Screen
    Sony VPL-HW50ES – Sony’s Best Home Cinema Projector
    Windows Vista : Installing and Running Applications - Launching Applications
    Most View
    Bamboo Splash - Powerful Specs And Friendly Interface
    Powered By Windows (Part 2) - Toshiba Satellite U840 Series, Philips E248C3 MODA Lightframe Monitor & HP Envy Spectre 14
    MSI X79A-GD65 8D - Power without the Cost
    Canon EOS M With Wonderful Touchscreen Interface (Part 1)
    Windows Server 2003 : Building an Active Directory Structure (part 1) - The First Domain
    Personalize Your iPhone Case
    Speed ​​up browsing with a faster DNS
    Using and Configuring Public Folder Sharing
    Extending the Real-Time Communications Functionality of Exchange Server 2007 : Installing OCS 2007 (part 1)
    Google, privacy & you (Part 1)
    iPhone Application Development : Making Multivalue Choices with Pickers - Understanding Pickers
    Microsoft Surface With Windows RT - Truly A Unique Tablet
    Network Configuration & Troubleshooting (Part 1)
    Panasonic Lumix GH3 – The Fastest Touchscreen-Camera (Part 2)
    Programming Microsoft SQL Server 2005 : FOR XML Commands (part 3) - OPENXML Enhancements in SQL Server 2005
    Exchange Server 2010 : Track Exchange Performance (part 2) - Test the Performance Limitations in a Lab
    Extra Network Hardware Round-Up (Part 2) - NAS Drives, Media Center Extenders & Games Consoles
    Windows Server 2003 : Planning a Host Name Resolution Strategy - Understanding Name Resolution Requirements
    Google’s Data Liberation Front (Part 2)
    Datacolor SpyderLensCal (Part 1)