plists are wonderful for storing small amounts of semi-structured data when you don’t want the overhead of using a full-blown database. OS X, as you have no doubt noticed, uses plists extensively to store configuration data.
I like to use plists to create configuration driven applications. On the App Store you can find TRIBE and The Green Book. These two application look very different, but they use exactly the same code base. The difference is a couple of plist configuration files. Our client is very happy with this, because they are busy churning out many different titles for the App Store using this method.
Reading a plist file from the application bundle just requires a few lines of code, and some error handling. I like to place that code in a nice convenience method like this:
- (id)readPlist:(NSString *)fileName { NSData *plistData; NSString *error; NSPropertyListFormat format; id plist; NSString *localizedPath = [[NSBundle mainBundle] pathForResource:fileName ofType:@"plist"]; plistData = [NSData dataWithContentsOfFile:localizedPath]; plist = [NSPropertyListSerialization propertyListFromData:plistData mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&error]; if (!plist) { NSLog(@"Error reading plist from file '%s', error = '%s'", [localizedPath UTF8String], [error UTF8String]); [error release]; } return plist; }
I’m not too fond of using id as return values or parameters to methods. I prefer stronger type checks, so I typically wrap the readPlist method in two methods that return either an array or a dictionary.
- (NSArray *)getArray:(NSString *)fileName { return (NSArray *)[self readPlist:fileName]; } - (NSDictionary *)getDictionary:(NSString *)fileName { return (NSDictionary *)[self readPlist:fileName]; }
Writing to a plist file is not much more difficult:
- (void)writePlist:(id)plist fileName:(NSString *)fileName { NSData *xmlData; NSString *error; NSString *localizedPath = [[NSBundle mainBundle] pathForResource:fileName ofType:@"plist"]; xmlData = [NSPropertyListSerialization dataFromPropertyList:plist format:NSPropertyListXMLFormat_v1_0 errorDescription:&error]; if (xmlData) { [xmlData writeToFile:localizedPath atomically:YES]; } else { NSLog(@"Error writing plist to file '%s', error = '%s'", [localizedPath UTF8String], [error UTF8String]); [error release]; } }
Note that writing to a file inside the app bundle is not good if you want your data to stick around after the application is upgraded since the bundle will be overwritten. You can look at the Apple’s SQLite code examples for code snippets on how to copy files out of the bundle before using them.