Saving data on the iPhone

Bryn Bellomy's picture

Over the past month or two, I've been fortunate enough to be able to put some work into an iPhone framework that interfaces with Drupal sites. In doing so, I've learned a number of things about the various Cocoa frameworks that might be useful to others. As such, I'm going to run a short series of blog posts documenting some of these discoveries.

First up is the subject of data storage -- particularly the storage of simple settings. There are several ways to accomplish this in the Cocoa touch framework. If your settings are fairly complicated and you don't expect your user to alter them very frequently, it's recommended that you hook into the Settings application (the way that Mail and Safari do, for example). Of course, this is cumbersome by virtue of the fact that you have to exit your app and start up Settings in order to change anything. If your user is tweaking settings frequently, this could spell a UI disaster.

Another option is simply to write settings to a file somewhere in your app's sandbox. For our Drupal/iPhone framework, I've adopted this approach. For most of our sites, I don't expect users to be dealing with very many settings -- username and password, of course, and perhaps a few other options tied into the Content Profile module. Therefore, while we can't take advantage of Apple's powerful Settings framework, data storage and retrieval is still very manageable.

One quick caveat that may seem silly at first. When it comes to interface design, do remember that with this approach you'll be using up valuable screen real estate with a "settings" button (and you can't begin to realize just how valuable this is until you start trying to assemble a complex UI). Plan for this well in advance or you'll find yourself redesigning your UI several times, perhaps even with completely different types of navigation controllers (which is a pain to redo). I began our app with a UINavigationBar, then switched to a UIToolbar, and finally recoded everything with a UITabBar when it became clear that the first two approaches were not appropriate. Not a very pleasant experience.

Objective C is still C, and you have all of the stdio functions at your disposal if you so desire. However, Cocoa comes with some great functions to assist you with file management and to keep you from writing to the wrong place in your app's sandbox. Here's a block of code to get us started. It saves a username and password to a binary file.

+ (BOOL) saveSettings:(NSString *)username password:(NSString *)password
{
	NSArray *dirArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
			NSUserDomainMask,
			YES);
 
	NSString *path = [NSString stringWithFormat:@"%@/settings.bin", [dirArray objectAtIndex:0]];
	NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:username, @"username", password, @"password", nil];	
	NSData *data = [NSPropertyListSerialization dataFromPropertyList:dict format:NSPropertyListBinaryFormat_v1_0 errorDescription:nil];
 
	if (data == nil) {
		NSLog(@"Error in SettingsDataController saveSettings");
		return NO;
	}
 
	NSLog(@"Writing to path: %@", path);
 
	if ([data writeToFile:path options:NSAtomicWrite error:nil] == NO) {
		NSLog(@"writeToFile error");
		return NO;
	}
 
	NSLog(@"writeToFile success");
	return YES;
}

Let's step through the first part of this save function. NSSearchPathForDirectoriesInDomains() returns an array of directories that match the search criteria. In this case, we're asking it to give us the documents directory for the app within the user's domain (rather than the systemwide domain). This is basically where you'll want to store most of your app's data, settings or otherwise. The second line of the function creates the full path to the settings file. In the third line, we're creating an NSDictionary object with the settings (be sure to end your dictionary with nil! Common mistake). The fourth line serializes the NSDictionary into an NSData object. If there are errors, the NSData object will be nil. If you skip a few lines down, you'll notice that the NSData class also provides methods for writing itself into a file. The NSAtomicWrite setting writes the data to a backup file first and then copies it to the specified path, preventing write errors from corrupting your settings. It's highly recommended that you write atomically.

Next time around I'll have some advice on caching settings to prevent unnecessary writes. Future articles will address sharing data between UITextViews and other ViewControllers, .xib files, using Interface Builder vs. building interfaces programmatically, and Drupal XML-RPC. Stick around!

Comments

Justin M.'s picture

While I like your code to write stuff to a data file, I'm curious why you don't still use Cocoa's NSUserDefaults framework, even though you are not using a Settings bundle outside of the app. It's meant to write data such as dictionaries to disk and can be extended to save arbitrary NSData as well. Like bindings on the Mac, NSUserDefaults is somewhat automated with the use of a Settings bundle, but you can still make use it of without implementing Settings.

AnoSD's picture

A person's travel is simple and easy, all the loss and pain, all stuffed into a large bag that golden, warm warmth of smiling faces, the sudden fall in this town, it is a little ambiguous at ease. The Louis vuitton handbagsfeatures introduced: the golden sequins dazzling the crowd is the most sparkling that you can hand the capacity to shoulder large, rare stylish and practical bag. Discount designer handbagson our website are sold well.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <blockcode>
  • Lines and paragraphs break automatically.
  • You can enable syntax highlighting of source code with the following tags: <blockcode>. Beside the tag style "<foo>" it is also possible to use "[foo]". PHP source code can also be enclosed in <?php ... ?> or <% ... %>.

More information about formatting options

CAPTCHA
Are you a robot? We usually like robots, but not in our comments.
Image CAPTCHA
Enter the characters (without spaces) shown in the image.