如何根据NSString类型键测试属性的存在和类型?

时间:2011-02-09 21:38:48

标签: properties css-selectors exists key-value-coding objective-c-2.0

在我的iOS项目中更新核心数据模型的过程中,我正在向服务器查询JSON对象,这些对象在某种程度上与我模型的托管实体相对应。我正在努力的最终结果是来自JSON输出的可靠更新解决方案。

对于此问题中的示例,我将命名核心数据管理对象existingObj和传入的JSON反序列化字典updateDict。棘手的部分是处理这些事实:

  1. 并非existingObj
  2. 中存在updateDict的所有属性
  3. 并非所有updateDict的属性都可用于extistingObj
  4. 并非所有类型的existingObj属性都与JSON反序列化属性匹配。 (某些字符串可能需要自定义的Objective-C包装器)。
  5. updateDict可能包含nil中未初始化(existingObj)的键的值。
  6. 这意味着在迭代更新的词典时,必须对来回进行一些属性测试。首先,我必须测试updateDict中是否存在existingObj的属性,然后使用KVC设置值,如下所示:

    // key is an NSString, e.g. @"displayName"
    if ([existingObj respondsToSelector:NSSelectorFromString(key)) {
        [existingObj setValue:[updateDict objectForKey:key] forKey:key];
    }
    

    虽然这部分有用,但我不喜欢我实际上正在测试displayName作为吸气剂的事实,而我即将调用setDisplayName:设定者(间接通过KVC) 。我更喜欢的是[existingObj hasWritablePropertyWithName :key],但是我无法找到的东西。

    这会产生子问题A:如果您只拥有该属性的名称,如何测试属性设置器?

    下一部分是我想根据其类型自动识别属性的地方。如果updateDictexistingObj都有一个用于键@“displayName”的NSString,则设置新值很容易。但是,如果updateDict包含@ @ niceShadeOfGreen的键@“color”的NSString,我想将其转换为正确的UIColor实例。但是如何在existingObj中测试接收属性的类型,以便我知道何时转换值以及何时简单地分配?我希望有一些类似 typeOfSelector:

    的内容
    if ([existingObj typeOfSelector:sel] == [[updateDict objectForKey:key] class]) {
         // regular assignment
    } else {
         // perform custom assignment
    }
    

    当然这是boguscode。我不能依赖于测试existingObj - 属性值的类型,因为它可能是单元化的或nil

    子问题B:如果您只拥有该属性的名称,如何测试属性的类型?

    我猜就是这样。我认为这必须是已经在这里的东西,但我找不到它。也许你们可以吗? 干杯,EP。

    P.S。如果您有更好的方法将自定义Objective-C对象与反序列化的JSON对象同步,请分享!最后,结果是最重要的。

1 个答案:

答案 0 :(得分:27)

如果要查询某个对象是否具有名为key的给定KVC键的setter,该键对应于声明的属性,则需要检查它是否响应名为setKey:的选择器方法(以set开头,大写key中的第一个字符,添加尾随冒号)。例如,

NSString *key = @"displayName";
NSString *setterStr = [NSString stringWithFormat:@"set%@%@:",
                       [[key substringToIndex:1] capitalizedString],
                      [key substringFromIndex:1]];

if ([obj respondsToSelector:NSSelectorFromString(setterStr)]) {
    NSLog(@"found the setter!");
    [obj setValue:someValue forKey:key];
}

两个评论:

  • 即使属性的名称设置符不符合上述模式,但它们也不符合KVC标准,因此可以安全地检查set<Key>:,因为您使用的是KVC设置相应的值。

  • KVC不仅使用setter方法。如果找不到setter方法,它会检查该类是否允许直接访问实例变量,如果是,则使用实例变量来设置值。此外,如果未找到setter方法或实例变量,它会向接收方发送-setValue:forUndefinedKey:,其类可能已覆盖引发异常的标准实现。这在Key-Value Coding Programming Guide中有描述。也就是说,如果你总是使用属性,那么检查setter方法应该是安全的。

至于第二个问题,不可能查询运行时以了解属性的实际Objective-C类。从运行时的角度来看,propertiesgeneral types有一个特定于实现的类型编码(例如方法参数/返回类型)。此类型编码对任何Objective-C对象使用单个编码(即@),因此NSString属性的类型编码与UIColor属性的类型编码相同他们都是Objective-C课程。

如果你确实需要这个功能,另一种方法是处理你的类并添加一个类方法,该方法返回一个字典,其中包含在该类和超类中声明的每个属性(或你感兴趣的属性)的键和相应类型,或者某种描述语言。您必须自己完成此操作并依赖于运行时期间不可用的信息。