views:

288

answers:

1

I'm writing an xml serialization class for objective-c.
The point is to give the class a class type and an xml file. It should return an instance with data.

I've got it working, and it does quite a bit - handles primitives (+nsstring), user defined classes and nsarrays. Doesn't handle pointers or C-arrays.
Obviously this relies heavily on reflection.

The question: When I set a value of an instance of some class, should I be checking if a property with the right name exists, or can I just set the variable using simple reflection?

This is the kind of code I've used so far:

id newClass = class_createInstance(NSClassFromString(elementName), sizeof(unsigned));
Ivar nameVar = class_getInstanceVariable([newClass class], "name");
if (nameVar != nil)
    object_setIvar(newClass, nameVar, [NSString stringWithString:@"George"]);

Also, after this kind of assignment, should I release anything?

+2  A: 

Uh... you usually don't need to get so low into the runtime to do what that code does. The following is fully functional and does exactly the same thing:

id newObject = [[NSClassFromString(elementName) alloc] init];
@try {
  [newObject setValue:@"George" forKey:@"name"];
@catch (NSException *e) {
  if ([[e name] isEqualToString:NSUndefinedKeyException]) {
    NSLog(@"%@ does not recognize the property \"name\"", elementName);
  }
}

//... do stuff with newObject
[newObject release];

If you need to put in other things, like floats or ints or structs, you can box them into an NSValue (or subclass), and then pass those to setValue:forKey:. For example:

NSNumber * aFloat = [NSNumber numberWithFloat:42.0];
[newObject setValue:aFloat forKey:@"aFloatIvar"];

NSRect frame = NSMakeRect(0, 0, 42, 54);
NSValue * aStruct = [NSValue valueWithBytes:&frame objcType:@encode(NSRect)];
[newObject setValue:aStruct forKey:@"aStructIvar"];
Dave DeLong
The problem with this code is that it doesn't work for primitive types. Is there a way to fix it?
Dror Speiser
Put your primitives into an NSValue object (like NSValue or NSNumber) and the internals will automatically unbox them.
Dave DeLong
NSValue wants "objCType:(const char *)type".How do I get the type? (Assuming without class_getInstanceVariable)
Dror Speiser
@Dror edited the answer
Dave DeLong
The code assumes prior knowledge of the type (float, NSRect).Is there an easy way to get the primitive type of a variable of a class so I can switch on it to do the above?
Dror Speiser
@Dror I don't know. What are you trying to do with this?
Dave DeLong