@Ahruman's answer is correct, if you're dealing with objects. Let me suggest some alternatives:
valueForKey:
: If you use [myObject valueForKey:@"myPropertyName"]
, it will return an object. If the property corresponds to some sort of primitive (int
, float
, CGRect
, etc), then it will be boxed for you into an NSNumber
or NSValue
(as appropriate). If it comes back as an NSNumber
, you can then easily extract a double representation (doubleValue
) and use that as an NSTimeInterval
to create an NSDate
. I would probably recommend this approach.
Special case each type. property_getAttributes()
returns a char*
representing all of the attributes of the property, and you can extract the type by doing this:
const char * type = property_getAttributes(class_getProperty([self class], "myPropertyName"));
NSString * typeString = [NSString stringWithUTF8String:type];
NSArray * attributes = [typeString components separatedByString:@","];
NSString * typeAttribute = [attributes objectAtIndex:0];
NSString * propertyType = [typeAttribute substringFromIndex:1];
const char * rawPropertyType = [propertyType UTF8String];
if (strcmp(rawPropertyType, @encode(float)) == 0) {
//it's a float
} else if (strcmp(rawPropertyType, @encode(int)) == 0) {
//it's an int
} else if (strcmp(rawPropertyType, @encode(id)) == 0) {
//it's some sort of object
} else ....
This is pedantically more correct than Louis's answer, because while most types have a single-character encoding, they don't have to. (his suggestion assumes a single-character encoding)
Finally, if you're doing this on a subclass of NSManagedObject
, then I would encourage checking out NSPropertyDescription
.
From these alternatives, you can probably see that letting the runtime box the value for you is probably simplest.
edit extracting the type:
From the code above, you can extract the class name like so:
if ([typeAttribute hasPrefix:@"@"] && [typeAttribute length] > 1) {
NSString * typeClassName = [typeAttribute substringWithRange:NSMakeRange(2, [typeAttribute length]-3)]; //turns @"NSDate" into NSDate
Class typeClass = NSClassFromString(typeClassName);
if (typeClass != nil) {
[object setValue:[self convertValue:self.value toType:typeClass] forKey:element];
}
}
And then instead of using class method categories to do the conversion (ie, [NSDate convertToDate:]
), make a method on self
that does that for you and accepts the desired type as a parameter. You could (for now) do it like:
- (id) convertValue:(id)value toType:(Class)type {
if (type == [NSDate class]) {
return [NSDate convertToDate:value];
} else if (type == [NSString class]) {
return [NSString convertToString:value];
} ...
}
Part of me is wondering, though: why on earth are you needing to do things this way? What are you making?