4

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?

Dror Speiser
  • 435
  • 4
  • 11

1 Answers1

6

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
  • 242,470
  • 58
  • 448
  • 498
  • The problem with this code is that it doesn't work for primitive types. Is there a way to fix it? – Dror Speiser Sep 07 '09 at 07:00
  • 1
    Put your primitives into an NSValue object (like NSValue or NSNumber) and the internals will automatically unbox them. – Dave DeLong Sep 07 '09 at 15:13
  • NSValue wants "objCType:(const char *)type". How do I get the type? (Assuming without class_getInstanceVariable) – Dror Speiser Sep 07 '09 at 21:18
  • 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 Sep 08 '09 at 18:31
  • @Dror I don't know. What are you trying to do with this? – Dave DeLong Sep 08 '09 at 19:14
  • @DaveDeLong - This is promising for me and may be my answer **if I fully understood it right now** I am absorbing the information here. But if you are so inclined to give me another answer for more points, please see my question here: http://stackoverflow.com/q/25538890/1735836 – Patricia Aug 28 '14 at 16:06