iPhone Predictions for 2009 Experienced iHouse Developer Wanted
Jan 16

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.

written by Nick \\ tags: , ,

7 Responses to “Reading and Writing plists”

  1. Olivia Says:

    Do you ever plan on doing any SQL tutorials?

  2. Nick Says:

    @Oliva: I have a couple of SQLite posts in the pipeline. Stay tuned.

  3. Eric Says:

    Nick,

    Thanks, nice, quick solution, well written, straight-and-to-the-point like I like it.

    Cheers, Eric.

  4. Ravi Says:

    Nick,

    Excellent and precise article. Good work.

    Ravi

  5. Mikethepike Says:

    I get an error on the first row;

    - (id)readPlist:(NSString *)fileName {

    “Did you mean readLink”

    Any idea?

    ;-)

  6. Daniel Says:

    You don’t have to write so much code, look into dictionaryWithContentsOfFile: or arrayWithContentsOfFile:

  7. Bitfool Says:

    Note that you cannot write over a plist file stored in your Bundle the way this method does… you don’t have that write permission. Strangely, if you use these methods in your app, during a given run of the app it will look to you like you have written over a plist file in your Bundle… you can change a value and save it, and read it back in as the new value. HOWEVER… run the app again (or look in the plist file) and it is as if you haven’t written to the file at all. And you haven’t! So I really don’t understand that particular behavior (why it appears to have worked), yet. If you really want to save data to a plist file, you have to use the regular document storage area… copy this plist file over to document storage, and save/write your file there.

Leave a Reply