Re: Experience with keyed archiving forward/backwards compatibility?
Re: Experience with keyed archiving forward/backwards compatibility?
- Subject: Re: Experience with keyed archiving forward/backwards compatibility?
- From: Graham Cox <email@hidden>
- Date: Sun, 01 Sep 2013 11:54:35 +0200
On 31/08/2013, at 6:48 PM, Marcel Weiher <email@hidden> wrote:
>
> On Aug 29, 2013, at 11:54 , Graham Cox <email@hidden> wrote:
>
>>
>>> So the whole automagic forward/backward compatibility that we’re supposed to get with keyed archives doesn’t actually pan out. If you want compatibility, you have to plan and code for it, just like with old-style archiving. And ideally, you have an externally defined format.
>>
>> Yes, you have to plan for it, but on a class-by-class basis, and only as necessary. It's not auto-magic, but it's generally pretty easy.
>
> So you’ve had good practical experience with forward/backward compatible designs?
Yes.
But let me qualify it :) By 'backward compatible' I mean files created by an earlier version of the app can be opened in a newer version, 'forward compatible' means the inverse: newer files can be opened by an older version of the app.
Backward compatibility is much easier than forward compatibility, and typically as the app evolves, that is what the primary focus is on, because on the whole you expect people to upgrade your app to a newer version, but they may have files created by the earlier version. Going in the other direction is only important if users with a variety of versions of your app share the files amongst each other - it's very rare for a single user to downgrade to an earlier version of your app.
So ensuring backward compatibility is something that is typically handled on a class-by-class basis, where the -encodeWithCoder simply writes what data it currently needs to, possibly with flags or versioning info so that the corresponding -initWithCoder is able to know which particular items are of interest. -initWithCoder: should also, as necessary, deal with older-format items it encounters when handed an old file.
Going the other way requires more cunning, and usually needs some support from version 1.0 of your app. I mentioned using a keyed unarchiver delegate - one way that can be used is to handle entire classes that the older app doesn't know about. It can substitute something else, perhaps the nearest superclass, or a placeholder so that newer files can be opened with reduced functionality. This can also help with backward compatibility, for example by translating older classnames to newer ones if you ever change them (that sounds unlikely, but it did happen in one product I developed due to a client insisting on changing a whole bunch of classnames after version 1.0). Newer versions can also provide alternate objects which cover the functionality present in the older apps, even if it's just a way to communicate to the user that they ought to upgrade. Example: a newer version of an app wrote out image data differently from an earlier version (which fell into the classic trap of archiving an NSImage object), but the newer app also archived a placeholder NSImage which included the text "version xxx is required to view this image", so that opening the newer file in an old app at least gave the user the hint. In that case it would have been possible to include image data in both formats, but we preferred to encourage the user to upgrade. The newer app could dearchive an old file's NSImage and convert it without a problem so a subsequent save would promote the file to the newer format.
That's as far as I've ever gone on forward compatibility. If you need something more robust than that I'm sure it can be done. As you said, some externally defined format helps a lot but the convenience and flexibility of keyed archiving is very attractive.
--Graham
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden