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

epo*_*gee 5 properties exists css-selectors key-value-coding objective-c-2.0

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

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

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

这意味着在迭代更新的字典时,必须对来回进行一些属性测试.首先我要测试是否updateDict存在属性existingObj,然后我使用KVC设置值,如下所示:

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

虽然这部分有效,但我不喜欢这样的事实,即我实际上是displayName作为一个吸气剂进行测试,而我正要打电话给setDisplayName:设定者(间接通过KVC).我更喜欢的是[existingObj hasWritablePropertyWithName:key],但是我找不到这样做的东西.

这使得子问题A:如果只有属性的名称,如何测试属性设置器?

下一部分是我想根据其类型自动识别属性的地方.如果两个updateDictexistingObj有一个NSString关键@"显示名",设置新的价值很容易.但是,如果updateDict包含@ @ niceShadeOfGreen的键@"color"的NSString,我想将其转换为正确的UIColor实例.但是我如何测试接收属性的类型,existingObj以便我知道何时转换值以及何时简单地分配?我希望有类似于NextSelector的东西:

if ([existingObj typeOfSelector:sel] == [[updateDict objectForKey:key] class]) {
     // regular assignment
} else {
     // perform custom assignment
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

小智 27

如果要查询某个对象是否具有key与所声明的属性相对应的给定KVC键的setter ,则需要检查它是否响应所调用的选择器方法setKey:(以setfirst 开头,大写第一个字符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];
}
Run Code Online (Sandbox Code Playgroud)

两个评论:

  • 尽管属性可以包含名称不符合上述模式的setter,但它们不符合KVC,因此您可以安全地检查,set<Key>:因为您使用的是KVC来设置相应的值.

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

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

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