fill the void

Posted
30 September 2009 @ 9pm

Tagged
development

4 Comments

Rereading Info.plist

Apple has a nice mechanism for storing important app bundle information outside of the application executable: Info.plist. All the applications in /Applications have one; just right-click on any app, select “Show Package Contents”, then click on “Contents”. The file elegantly houses many facts (version, name, copyright) about your app. And Apple has a straight-forward API to get at that data: [[NSBundle mainBundle] infoDictionary]. The call returns an NSDictionary filled with key-value pairs from the Info.plist file. This workflow allows me to easily add my own key-value pairs to the file and quickly access them in code.

Recently, I wanted to read the key-value pair dynamically. That way, the user could change the value at any time, and within a minute, the app would use the new value. This proved harder. As it turns out, Apple optimized the infoDictionary query, so that it caches the contents at startup and returns that cached version through the application lifetime. If the user modified the key-value pair, that change wouldn’t show up until the next startup. Instead of using that builtin method, I had to read the Info.plist file directly. See the code below.

// [[NSBundle mainBundle] infoDictionary] is cached at app startup, so we need to read the file directly for latest data.
NSString *infoPlistFilePath = [NSString stringWithFormat:@"%@/Contents/Info.plist", [[NSBundle mainBundle] bundlePath]];
NSString *infoDictionary = [NSDictionary dictionaryWithContentsOfFile:infoPlistFilePath];
NSString *value = [infoDictionary valueForKey:@"InfoPlistKey"];

UPDATE: This is a lesson in design. While the code does function as described, I now agree that no user should be subjected to this workflow. Check out my longer explanation about the feature’s design.


4 Comments

Posted by
Stuart
1 October 2009 @ 5am

I’ve no idea if there is a formal stance on this from Apple, but I suspect you are misusing the info.plist file. Sure, you can put your own tagged values in, but I don’t feel that info.plist is to be used as a dynamic store. Since it is so easy to, why not just create another file containing a dictionary, and use that? Or store the keyed info in your app’s prefs file, and use notification methods to advice dependent parts of your app whenever keyed values are changed.


Posted by
Michelle
1 October 2009 @ 10am

I agree with Stuart. It’s trivial to create a second plist and set up a Config or State class to get/set values. Add one to your template project and all you have to do is change the keys and default values and implement some getters and setters. (I strongly prefer to have a single object interface for data files, rather than having accessors to the data strewn all over my GUI and behavioral code.)


Posted by
fill the void – Design Iteration
1 October 2009 @ 11pm

[...] feature I alluded to in my “Rereading Info.plist” post is a logging preference. It has two requirements: user-configurable (i.e. not code) but not [...]


Posted by
bdunagan
2 October 2009 @ 12am

Yep, totally agree now. I updated this post and wrote a longer explanation in a separate one. Thanks for the swift comments! I already re-implemented the feature! :)


Leave a Comment