Property Lists: How to use it to provide easy exchangeable default data to the user? - iphone

I want to ship some default data with my app. This data can be stored perfectly in a property list. The strucure is simple:
Root
0
animalType = cat
animalName = Tom
1
animalType = dog
animalName = Rambo
I thought: When I use a property list rather than hard-coding it somewhere, then I could easily provide more defaults to choose from after the app is distributed already. If I would hard-code it, I would have to provide heavy upgrades every time, and Apple would take weeks to let them pass.
But there's one thing I don't get. I make that property list manually in Xcode and put that in my Resources group. As far as I know, Xcode would compile it into some binary format. In my app I would use NSPropertyListSerialization to create a NSDictionary out of it. But this property list would not get placed into the documents directory of the sandbox, right? So if the application would download an update of that property list some time in the future, the update would have to go into documents dir, but the app would still look at the old plist in the root, right? Where to put it? Must I copy it to documents, just like an sqlite database?
And the other thing: When I edit the plist and provide the whole thing as an XML for download/update from a server, then of course that thing would not be "compiled" into some binary format. How would that work? Would NSPropertyListSerialization have trouble reading it? Must I compile that thing every time with XCode and let the app download some binary stuff?

There are two commonly used property list formats: proprientary binary format and xml format (DTD). You can use either of them, and NSPropertyListSerialization will detect automatically, which one is used for your data when de-seralizing.
XML format is more verbose, but it's simple to generate. If you're publishing data from server, you might consider generating xml plist, and compress it with gzip or something.
Now to your first question about where to store the data. To make application payload smaller you might first check documents directory for updated plist, and if it is not present - load default plist from your application bundle.

One general approach used is to always copy plists or other updated elements into the application documents directory - then you just always load from there, and replace when there is an update.
Or you could pre-load the data into a database, download plist updates and refresh the database entries at that time.

Related

Store Small Number of NSMutableArrays (with plist)?

I need store just 10 arrays in my app, which I can change from time to time. What would the best way to do this be?
I have been looking into writing to a plist, is this a good idea?
Each of the 10 arrays will have 10 objects (just strings).
You could create an NSDictionary (or rather the mutable version in your case) and populate it with your arrays. Then you could write them to disk with
writeToFile:atomically:
At start you could check whether your path is valid (meaning your dict exists) and assign it to your iVar in code for example with
initWithContentsOfFile:
The advantage is that the underlying representation is a plist for the NSDictionary (or NSMutableDictionary). So you are good to go here as well and as your objects within the arrays conform to NSCoding they all know how to encode them for writing to disk.
Using a plist file is a fine way to go as long as you don't need to interoperate with a non-Objective-C codebase (e.g. share with a Windows app, send the data to a server, etc.)

How can I detect when a NSPersistentStore needs to be saved?

I have an iOS application where I use coreData to store my "documents". They all share a common NSManagedObjectContext, and I frequently save the context.
I would like to keep track of the last modification date for the various "documents" (where each one is a separate NSPersistentStore) and store the date on a particular unique "root" object that each store has.
I could try to keep the modification time stamp up to date while the document is being modified, but it would be cleaner and more robust if I could just find out which persistent stores need saving at the time I am saving the context.
I can't find any way to detect if a persistent store needs saving. I can query the NSManagedObjectContext to see which managed objects need saving, although I can't find an easy way to see which store an object belongs to.
It seems like this is not such a strange thing to do and core data has all of the information that I am looking for, but I am having trouble finding an easy way to get access to that data.
Does anyone know of an easy way?
If I can't find an easier way, I will simply loop over the deleted / modified / inserted objects from the context, and write special code for each entity type to determine the store that the object belongs to.
Thanks in advance for any help!
Ron
[[managedObject objectID] persistentStore] is the persistent store you're looking for (or possibly nil if the object has not been saved yet).
The documentation suggests that it's nil if you've assigned it to a store but haven't saved; I'm not sure that this is true (and I don't see anywhere else where this info might be saved). I'd check it behaviour on 3.x, 4.x, and 5.0 beta if you have access to it.

How to save / reload a custom array to a plist

I'm loading in data from an sqlite database, storing the values i load from there in the instance variables of a custom class, and then adding this class to a mutable array, which i'm then assigning to the instance variable of my view controller, for use in a tableview.
I would, though, like to save this array into a .plist file in the documents directory on the app's first run, so that i can retrieve the whole object from there on load, rather than pulling all 214 items from the database.
Is this approach a better option? if so, could someone please help provide me with some code that will allow me to save an array of my custom classes as a .plist file? I've come across a lot of sample code on the web, but none of it works correctly.
I'd like to:
Check for the existence of the my_data.plist file.
If it exists, read it in as the array.
If it doesn't, read the data from the sqlite db into an array.
save this data to a .plist so that it can be read in faster later.
Thanks guys, appreciate any help you can give me.
It will probably be faster to just get the values from your database on launch. There will almost definitely be more cost to parse a plist containing these values than to just get them all from the database, unless the query you have to use to get them from the database is really slow.
Note also that once you're saving these objects to a plist on disk, you're actually going to be hurting performance of your program because you'll be writing your objects to disk twice and reading them from disk twice. You'll also be introducing opportunities for discrepancies between the plist and the database in the event of a bug or a crash.
That said, the only way to prove this to yourself may be to implement and profile both options, and compare actual numbers. Check out #occulus's link, above, for instructions how to read and write a plist. To profile your app, try using Instruments
When I google for "nsarray writetofile custom object" (no quotes) and click on the first link in the results, I find a really useful page.
For the record, it's this:
http://www.cocoabuilder.com/archive/cocoa/240775-saving-nsarray-of-custom-objects.html

Where can i find a good example of archiving objects for persistence for the iphone sdk

I have an object that contains about half a dozen properties. I expect to save maybe a dozen or more of these objects to my documents folder. My solution is to save the data using NSEncoding and NSKeyed/Archiver/Unarchiver. Anyone have a better strategy or approach.
NSKeyedArchiver/Unarchiver will work fine. If each file only has a half dozen properties, you might consider whether putting the entire object list in one file would be simpler for you to load/save/keep consistent.

Versioning a persistent keyed archive?

For my current app I'm using the NSKeyedArchiver approach to persist my objects to the iPhone between launches. I'm wondering if it makes sense to tag this file when it's created with a version number so that in the future when the app revs we'll know what kind of data we're dealing with should migration be necessary. Is this recommended for something as simple as an NSArray of custom objects that are serialized with NSKeyedArchiver? If so how/where to stash the version number?
Thanks!
If you feel like the format will change, then yes, you'll want some way to detect which version of the file you're working with. A simple way to do this (since you're using NSArray) would be to simply add the version number as an NSNumber to either the beginning or end of the array. Alternatively, for a more complicated approach that doesn't actually change the files, you could store the information in a separate file (say, using an NSDictionary that links the file name and version number). Or, you could use the user defaults system to store it, and if it's frome an older version, update the file and the user defaults key.
I wouldn't use the second method, unless you're dealing with multiple keyed data files. Of those three, I'd probably choose the last, but there may be some other way to do it that makes more sense.