【问题标题】:How to test property existence and type based on NSString typed key?如何基于 NSString 类型键测试属性存在和类型?
【发布时间】:2011-06-24 11:05:18
【问题描述】:

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

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

  1. 并非existingObj 的所有属性都存在于updateDict
  2. 并非updateDict 的所有属性都在extistingObj 中可用。
  3. 并非所有类型的 existingObj 的属性都与 JSON 反序列化属性匹配。 (某些字符串可能需要自定义的 Objective-C 包装器)。
  4. updateDict 可能包含 existingObj 中未初始化 (nil) 的键的值。

这意味着在迭代更新的字典时,必须来回对属性进行一些测试。首先我要测试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 包含键 @"color" 的 NSString,即 @"niceShadeOfGreen",我想将其转换为正确的 UIColor 实例。但是如何测试existingObj 中接收属性的类型,以便知道何时转换值以及何时简单地分配?我希望有类似 typeOfSelector:

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

当然这是假代码。我不能依赖测试existingObj-property 值的类型,因为它可能是未初始化的或nil

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

我想就是这样。我想这一定是这里已经存在的东西的欺骗,但我找不到它。也许你们可以?
干杯,EP。

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

【问题讨论】:

  • 我建议您只需查询updateDict 的键你知道 并忽略所有其余的。
  • 从上面的例子来看,这确实是一个可行的选择。然而,在现实世界的场景中,这会使托管对象的修改和更新变得非常复杂。这些对象由 30 多个键/属性组成,其中大部分是 NSString 或 NSNumber。如果上面的问题有解决方案,那么在双方都添加或修改原始类型时,同步不需要修改。

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


【解决方案1】:

如果你想查询一个对象是否有一个给定KVC键的setter,称为key,它对应于一个声明的属性,你需要检查它是否响应一个名为setKey:的选择器方法(以@987654326开头@,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];
}

两个备注:

  • 即使属性的 setter 名称不符合上述模式,它们也不符合 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 类。

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

【讨论】:

  • 非常有价值的输入@Bavarious。我没有想到具有相应类型的字典,这是迄今为止最优雅的解决方案!从 JSON 中的服务器响应更新本地模型时,这不是一个常见问题吗?有没有更好的同步解决方案?干杯,EP。
  • 这实际上是下一个问题的主题,我暂时关闭这个问题。谢谢!
  • 真的很酷,但是这对关键路径如何(有效地)起作用?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-07-27
  • 1970-01-01
  • 1970-01-01
  • 2020-10-16
  • 2020-06-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多