Versioning a persistent keyed archive? - iphone

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.

Related

How do you access the storage map for a cache class programmatically?

I'm trying to create a method that will automatically create something I can save and use later, which will let me automate data migration from one version of a class to the next.
When I compile a normal persistent class, a "storage" gets created, and I would like to be able to archive some code that would let me recreate this "old storage" so I could access an "older version" from a global and map the values into the current mapping of the class. I have objectgenerator methods that will save a version with every record, and detect if the "current version" of the class code is different from the version saved in the data record itself, but I'm not sure how to retain what the "old" version actually looked like so I can auto-migrate the data from the "old to the new". To do this, I'm thinking that being able to read what the current storage is at compile time, I should be able to save that value elsewhere and create a durable "version reader" so I can migrate the data forward without having to actually have the programmer do the work.
Does this seem like a reasonable approach? and if so, can anyone point me to where, at compile time, the storage values are so I can do the saving of the data?
(or should I be looking at cloning some part of the generated %Save() method chain at compile time to a version specific save attached to "something else" (not sure what, but 'something'))
This question and answer originally appeared in the InterSystems Developer Community https://community.intersystems.com/post/how-do-you-access-storage-map-cache-class-programmatically
In a database, your most important asset is your data -- business logic and code comes a close second. There should at least be someone paying attention to the data slots for sanity, even though in most cases, there is nothing to do. At the very least, any developer adding or modifying properties should "diff" the storage definition when submitting code to the source repository. The class compiler by default will handle everything correctly.
The simplest and best way to move from one version of a class to the next is to keep the same storage definition. The class compiler will create slots for any new properties and is completely non-destructive and conservative. When I retire properties, I generally manually rename the storage slot and give it a prefix such as zzz. This allows me to explicitly clean up and reuse these slots later if I so choose.
For the type of before/after compile triggers you are looking for, I would use the RemoveProjection/CreateProjection methods of a projection class which provide "a way to customize what happens when a class is compiled or removed".
You can use %Dictionary.CompiledStorage and related classes(Data) to have full access to the compiled storage definition of a class.
3a. An alternate approach is to use XSLT or XML parsing to read the storage definition from the exported class definition. I would only use this alternative if you need to capture details for separate source control purposes.
The simplest storage definitions use $ListBuild slots and a single global node. When subclasses and collection properties are used, the default storage definition gets more complicated -- that is where you will really want to stick to the simple approach (item 1).

Mongo DB Collection Versioning

Are there any best practices or ways we can use to version a collection or objects in a collection in Mongo DB?
The requirement of versioning a collection is because, the objects in the collection maybe added with new attributes going forward but the already added objects (i.e. old objects) will not be having these attributes and the values for these new attributes. So on retrieval, we need to make sure, the code is not broken in de-serializing the different versions of the same object in the collection.
I can think of adding a version attribute to the objects explicitly, but are there any better built in alternatives in Mongo DB for handling this versioning of objects and/or collections.
Thanks,
Bathiya
I guess the best approach would be to update all objects in a batch process when you start using the new software on the server, since otherwise you’ll never know when an object will be updated and you’ll need to keep the old versions of those forever around.
Another thing what I’m doing so far, and it worked (so far), to have the policy to only allow adding new properties to the object. This way in worst case the DB won’t have all the data, but that is fine with all the json-serializers I know. But this means you aren’t allowed to delete or rename properties as well as modifying their type (from scalar value to object, array; from object to scalar, array; …).
Since usually I want to store additional information instead of less, this seems like a good solution without any real limitation for me.
If you need to change the type because scalar value isn’t enough, you can still create some code around which would transform it for every object which has the old value into the new one. And if a bulk update from your side is able to perform the changes I’d still do it but sometimes it needs user input.
For instance if you used to save passwords only as md5-hash it was a scalar value. But someone told you, they should be stored as sha512 with a salt together, now you need an object field for the password, you could call it password_sha512 where you store the salt and the hashed password.

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.

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

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.