在Objective-C中确定属性是否为int,float,double,NSString,NSDate,NSNumber等

Kev*_*tre 14 iphone cocoa objective-c

我需要确定一个对象的属性(通过名称传递)类型,以便从XML执行反序列化.我有一些通用的伪代码(但是我不确定如何在Objective-C中执行这些比较):

id object = [[[Record alloc] init] autorelease];

NSString *element = @"date";
NSString *data = @"2010-10-16";

objc_property_t property = class_getProperty([object class], [element UTF8String]);
const char *attributes = property_getAttributes(property);

char buffer[strlen(attributes) + 1];
strcpy(buffer, attributes);

char *attribute = strtok(buffer, ",");
if (*attribute == 'T') attribute++; else attribute = NULL;

if (attribute == NULL);
else if (strcmp(attribute, "@\"NSDate\"") == 0) [object setValue:[NSDate convertToDate:self.value] forKey:element];
else if (strcmp(attribute, "@\"NSString\"") == 0) [object setValue:[NSString convertToString:self.value] forKey:element];
else if (strcmp(attribute, "@\"NSNumber\"") == 0) [object setValue:[NSNumber convertToNumber:self.value] forKey:element];
Run Code Online (Sandbox Code Playgroud)

我查看了class_getPropertyproperty_getAttributes,但是我仍然不确定如何进行上述比较.

Dav*_*ong 37

@ Ahruman的回答是正确的,如果你正在处理对象.我建议一些替代方案:

  1. valueForKey::如果使用[myObject valueForKey:@"myPropertyName"],它将返回一个对象.如果属性对应于某种原始的(int,float,CGRect等),那么它将被盒装你到一个NSNumberNSValue(如适用).如果它作为一个回来NSNumber,你可以轻松地提取一个双表示(doubleValue)并将其用作NSTimeInterval创建一个NSDate.我可能会推荐这种方法.
  2. 每种类型的特殊情况. property_getAttributes()返回char*表示属性的所有属性,并且您可以通过执行以下操作来提取类型:

    const char * type = property_getAttributes(class_getProperty([self class], "myPropertyName"));
    NSString * typeString = [NSString stringWithUTF8String:type];
    NSArray * attributes = [typeString componentsSeparatedByString:@","];
    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 ....

    这比路易斯的答案更为正确,因为虽然大多数类型都有单字符编码,但他们没有必要.(他的建议假定采用单字符编码)

  3. 最后,如果您在子类上执行此操作NSManagedObject,那么我会鼓励您查看NSPropertyDescription.

从这些替代方案中,您可能会看到让运行时框为您提供的值可能是最简单的.

编辑提取类型:

从上面的代码中,您可以像这样提取类名:

if ([typeAttribute hasPrefix:@"T@"] && [typeAttribute length] > 1) {
  NSString * typeClassName = [typeAttribute substringWithRange:NSMakeRange(3, [typeAttribute length]-4)];  //turns @"NSDate" into NSDate
  Class typeClass = NSClassFromString(typeClassName);
  if (typeClass != nil) {
    [object setValue:[self convertValue:self.value toType:typeClass] forKey:element];
  }
}
Run Code Online (Sandbox Code Playgroud)

然后,不是使用类方法类别来进行转换(即,[NSDate convertToDate:]),self而是为此创建一个方法,并接受所需类型作为参数.你可以(现在)这样做:

- (id) convertValue:(id)value toType:(Class)type {
  if (type == [NSDate class]) {
    return [NSDate convertToDate:value];
  } else if (type == [NSString class]) {
    return [NSString convertToString:value];
  } ...
}
Run Code Online (Sandbox Code Playgroud)

然而,我的一部分想知道:为什么你需要以这种方式做事?你在做什么?