views:

1670

answers:

3

Is there any means of reflection in Objective-C that would allow you to write generic NSCoding implementations by inspecting the public properties of an object and generating generic implementations of encodeWithCoder: and initWithCoder: .

I'm thinking of something like XStream for Java that allows a generic way to serialize and deserialize Java objects using reflection. Even better would probably be some means of marking properties as things you'd want to serialize or that are transient (like the transient keyword in Java).

I've been reading the documentation on Archives and Serializations Programming Guide for Cocoa. I understand that you want some control over the serialization of your objects, but it is generally a symmetrical process and it seems odd to have to reverse what is coded for serialization to deserialize it. I'm a believer of DRY (don't repeat yourself).

+10  A: 

Not only is it possible, but I have a friend who's taken a stab at doing precisely that. (You can see his blog about it here.) The reflection is done using the Objective-C runtime functions documented in the Objective-C 2.0 Runtime Reference. Take a look.

Note, however, that this will only work if you want the generic behavior of saving all the instance variables. You might not want an NSView to save its superview, though; in such cases, the generic case wouldn't work.

You could conceivably distinguish between things-to-serialize and things-not-to-serialize by declaring properties for any instance variables you want to save and leaving any other variables "hidden", but that's twisting the whole purpose of properties to a small benefit. I wouldn't recommend it.

BJ Homer
+3  A: 

(I am the author of the blog post linked to in BJ Homer's comment). There are a couple caveats to using the code:

  1. The target class has to be KVC-compliant. If you're using Objective-C 2.0 properties for your ivars, then you're all set. Otherwise, you need to make sure that your class is set up to properly respond to valueForKey: and setValue:forKey: methods.
  2. The code uses an undocumented "feature" of the runtime to recursively conform ivar classes to NSCoding. When compiled, almost all typing information (AFAIK) is stripped out of the code, yet in order to save the ivars, they have to conform to NSCoding as well. I discovered that if the ivar is an object and I call ivar_getTypeEncoding() on it, I'll get a c string back that looks something like: {#IVAR_CLASS} (Example: {#NSString}). What I do is get the string between the # and }, create a Class object using NSClassFromString, and recurse on that.
  3. This code will save ALL the ivars.
  4. Use at your own risk (of course)

I wrote this mainly as a proof of concept, and there are many instances when this code would fail spectacularly. For example, in object A has an ivar for B, and B has an ivar for A, then using the code to serialize one or the other would (I believe) cause an infinite loop.

Nevertheless, I think it's pretty freaking awesome that Objective-C even allows you to do stuff like in the first place.

Cheers,

Dave DeLong

Dave DeLong
+1  A: 

Check out RMModelObject:

http://www.realmacforge.com/svn/trunk/RMModelObject/

However, note that ObjC Runtime stuff works in 10.5, and in the Simulator, but not on an actual iPhone. Found that out the hard way.. Maybe OS 3.0 finally supports it, but I haven't checked.

Ryan