iPhone SDK Articles

Saturday, August 16, 2008

Application Preferences - Part 2


Welcome to the second part of Application Preferences tutorial, where I show you how to save the preferences.


Welcome to the Part 2 of Application Preferences tutorial. In this tutorial we will set the default values for this application. We do this in applicationDidFinishLoading method. If you haven't read the Part 1 of this tutorial, you can read it here. All the files references here are created in the first part of this tutorial.

Before we begin, open Root.plist file and set the Title to "RootPList". If you do not set a title then the following code may not work. That is what my experience has been.

FileName: ApplicationPreferencesTutorialAppDelegate.m
//It is here that we set the defaults
NSString *textValue = [[NSUserDefaults standardUserDefaults] stringForKey:@"textEntry_Key"];

//If the first value is nil, then we know that the defaults are not set.
if(textValue == nil)
{
//Get the bundle path
NSString *bPath = [[NSBundle mainBundle] bundlePath];
NSString *settingsPath = [bPath stringByAppendingPathComponent:@"Settings.bundle"];
NSString *plistFile = [settingsPath stringByAppendingPathComponent:@"Root.plist"];

//Get the Preferences Array from the dictionary
NSDictionary *settingsDictionary = [NSDictionary dictionaryWithContentsOfFile:plistFile];
NSArray *preferencesArray = [settingsDictionary objectForKey:@"PreferenceSpecifiers"];

//Temporary Variables
NSDictionary *item;
NSString *textEntry_Key;
NSString *readOnly_Key;
NSString *toogle_Key;
NSString *slider_Key;
NSString *colors_Key;

//Loop through the array
for(item in preferencesArray)
{
//Get the key of the item.
NSString *keyValue = [item objectForKey:@"Key"];

//Get the default value specified in the plist file.
id defaultValue = [item objectForKey:@"DefaultValue"];

if([keyValue isEqualToString:@"textEntry_key"])
textEntry_Key = defaultValue;

if([keyValue isEqualToString:@"readOnly_key"])
readOnly_Key = defaultValue;

if([keyValue isEqualToString:@"toogle_key"])
toogle_Key = defaultValue;

if([keyValue isEqualToString:@"slider_key"])
slider_Key = defaultValue;

if([keyValue isEqualToString:@"colors_key"])
colors_Key = defaultValue;
}

//Now that we have all the default values.
//We will create it here.
NSDictionary *appPrerfs = [NSDictionary dictionaryWithObjectsAndKeys:
textEntry_Key, @"textEntry_key",
readOnly_Key, @"readOnly_key",
toogle_Key, @"toogle_key",
slider_Key, @"slider_key",
[NSNumber numberWithInt:1], @"slider_key",
[NSNumber numberWithInt:1], @"colors_key",
nil];

//Register and save the dictionary to the disk
[[NSUserDefaults standardUserDefaults] registerDefaults:appPrerfs];
[[NSUserDefaults standardUserDefaults] synchronize];

We first have to check, if the defaults for this application has been set or not. If it is not then we have to create it, register it and sync it with the application.

In the source code above, I check if a value exists for a given key or not. If the value is nil then I know that the defaults have not been set.

We start by getting the path to our plist file and it is stored in the variable called plistFile.

//Get the bundle path
NSString *bPath = [[NSBundle mainBundle] bundlePath];
NSString *settingsPath = [bPath stringByAppendingPathComponent:@"Settings.bundle"];
NSString *plistFile = [settingsPath stringByAppendingPathComponent:@"Root.plist"];

We then create a dictionary with the contents of the property list file (plist file) and get the "PreferenceSpecifiers" into an array.

//Get the Preferences Array from the dictionary
NSDictionary *settingsDictionary = [NSDictionary dictionaryWithContentsOfFile:plistFile];
NSArray *preferencesArray = [settingsDictionary objectForKey:@"PreferenceSpecifiers"];

Custom preferences were added into its own Array, so we will be able to loop through all the items in the array. We create temporary variables to hold the value and the key for every item we get from the array.

//Now that we have all the default values.
//We will create it here.
NSDictionary *appPrerfs = [NSDictionary dictionaryWithObjectsAndKeys:
textEntry_Key, @"textEntry_key",
readOnly_Key, @"readOnly_key",
toogle_Key, @"toogle_key",
slider_Key, @"slider_key",
[NSNumber numberWithInt:1], @"slider_key",
[NSNumber numberWithInt:1], @"colors_key",
nil];

//Register and save the dictionary to the disk
[[NSUserDefaults standardUserDefaults] registerDefaults:appPrerfs];
[[NSUserDefaults standardUserDefaults] synchronize];

Now that we have all the data we need, we will create another dictionary object with our key-value data. We then register the dictionary object using the registerDefaults method. registerDefaults will register the dictionary with a NSRegistrationDomain, which we do not need to create manually. It is simple a place where temporary variables can be set by the application. Then we call the synchronize method and it will write any modifications made to the domain to the disk.

If you have already downloaded this application, then you need to delete it from the simulator and run it again from XCode to see the default values is set.

This concludes the Part 2 of Application Preferences tutorial. You can download the source code here.

Happy Programming
iPhone SDK Articles

13 comments:

Phil said...

Thank you for the tutorial, all of the content was clear to me.

However, I still have to open questions:

1.) Is it possible to invoke the preferences screen from within an application?

2.) Once I entered data in the text box in the preferences the keyboard stays up, is it possible to hide it again after data input?

Thanks,
Phil

jai said...

Hi Phil,

Preferences can only be opened from "System" application. You would have to create your own custom screen, if you need preferences to show up in your application.

Since the data entry for application preferences is controlled by the SDK/iPhone, I do not think it is possible to hide the keyboard after the user has done entering text. To save the text, the user has to go back to screen by clicking the left button.

Thanks,
iPhone SDK Articles

PunkStar Studios said...

I'm wondering how I can change the values from within the program (from one of the view controllers).
Let's say a default value was for a particular field in a particular window/view.
The user changes that value...
How do you write that value back to the preferences?
I've tried (with no success):

NSDictionary *appPrerfs = [NSDictionary dictionaryWithObjectsAndKeys:
lblName.text, @"NAME",
lblAddress.text, @"ADDRESS",
nil];

[[NSUserDefaults standardUserDefaults] registerDefaults:appPrerfs];
[[NSUserDefaults standardUserDefaults] synchronize];

jai said...

To Punkstar Studios

call "resetStandardUserDefaults" instead of "synchronize" when values are not set in applicationDidLoadMethod.

So the last two lines will look like

[[NSUserDefaults standardUserDefaults] registerDefaults:appPrerfs];
[NSUserDefaults resetStandardUserDefaults];

I tried this solution and it works. Let me know how it works out.

Happy Programming,
iPhoneSDKArticles

ben syverson said...

Hi,

Thanks for this article! I've found that you can actually get to your settings in one line of code:

NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Root" ofType:@"plist" inDirectory:@"Settings.bundle"]];

You don't have to rename your Root.plist file, either...

Happy coding,

- ben syverson

iPhone SDK Articles said...

@ben Thanks Ben, that works for sure.

Happy Programming,
iPhone SDK Articles

anil said...

i have followed both the tutorials here....The preference bundle is working fine with xcode...But when i make the binary of the project and try in any other system the application preference is not coming in settings....can anyone help me in this....

iPhone SDK Articles said...

@anil Is it possible for you to send me your source code?

Does it now show up in the IB?

Happy Programming,
iPhone SDK Articles

Anonymous said...

Anil, I am having the same issue. How did you solve this?

abraginsky said...

How do you test to see if the prefs are set if the prefs only consist of boolean values? Testing a boolean against nil isn't allowed and it will just be NO if not set by default.

iPhone SDK Articles said...

@abraginsky You do need to set the defaults when the app is launched for the first time. Usually the programmer would know the defaults and would set it accordingly.

Does this help?

Happy Programming,
iPhone SDK Articles

Suzanna said...

Like Anil I can't get my settings to display on the device, but all works fine within xcode. Has anyone figured this out?

andy said...

Thanks for the app preference tutorials..

1.Pls help me how can I change the font properties in PSGroupSpecifier......

2. How to add icon for child pane?