views:

428

answers:

1

Version 1.0 of an application has a data model, which is saved/loaded using the NSKeyed(Un)Archiver classes, as all model classes adhere to the NSCoding protocol. Say the following hierarchy exists:

-> Houses (NSMutableArray)
-> -> House (Custom Object)
-> -> -> Color (3 ints, RGB)
-> -> -> Number of Residents (int)

Say that there are legacy files stored in such a manner, but need to be loaded into version 2.0 of the application for backwards compatibility, using the following newer data model:

-> Neighborhood (Maintains NSMutableArray, among other properties)
-> -> TownHouse
-> -> -> Color (3 ints, RGB)
-> -> -> Occupants (NSMutableArray)
-> -> (Other types of houses)

Obviously, some data will be missing and will need to be filled in. Eg. a basic "Occupant" object will need to be created for each of the "number of residents" that existed before. What I'm looking for is a way to programmatically load in the previous data model, especially if I only have a list of the classes/hierarchy, and not the .m/.h files themselves.

So what I want to do is (assuming I have a file Houses.data, which was serialized using the Houses array):

NSFile *legacyFile;
Neighborhood *hood = [Neighborhood neighborhoodFromLegacyFile:legacyFile];

Any ideas?

+1  A: 

Hi Craig,

I think the trick here is to use the setClass:forClassName: function provided by NSKeyedUnarchiver. It allows you to say: "Use class TownHouse to deserialize all instances of class House."

Then you need to modify your TownHouse's initWithCoder: function to decode either hierarchy. You might accomplish this by calling decodeObject or decodeObjectForKey: and then using isKindOfClass: to see what type of object you're dealing with. You can also use containsValueForKey: to check for certain keys before trying to read them out.

I hope that helps!

Ben Gotow
It kind of works! One issue is that the "Houses" array, along with a few other objects, were wrapped in an NSArray.This made it easy to serialize one object, by calling [NSKeyedArchiver archivedDataWithRootObject:(NSArray *)topLevelArray];To get this back out, I had been using [NSKeyedUnarchiver unarchiveObjectWithData:topLevelArrayData];.So how can I use the unarchiveObjectWithData: method, since it's a class method, with an instance of a custom NSKeyedUnarchiver?
craig
Hey Craig! The NSKeyedUnarchiver class provides the setClass:forClassName: function at both the class and instance levels, so you can actually say [NSKeyedUnarchiver setClass:forClassName:] and then use [NSKeyedUnarchiver unarchiveObjectWithData:topLevelArrayData]. You can create an instance of NSKeyedUnarchiver if you want, but it's not required. It should use the settings you provided before hand either way.
Ben Gotow