在我的iOS项目中更新核心数据模型的过程中,我正在向服务器查询JSON对象,这些对象在某种程度上与我模型的托管实体相对应。我正在努力的最终结果是来自JSON输出的可靠更新解决方案。
对于此问题中的示例,我将命名核心数据管理对象existingObj
和传入的JSON反序列化字典updateDict
。棘手的部分是处理这些事实:
existingObj
updateDict
的所有属性
updateDict
的属性都可用于extistingObj
。existingObj
属性都与JSON反序列化属性匹配。 (某些字符串可能需要自定义的Objective-C包装器)。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];
}
虽然这部分有用,但我不喜欢我实际上正在测试displayName
作为吸气剂的事实,而我即将调用setDisplayName:
设定者(间接通过KVC) 。我更喜欢的是[existingObj hasWritablePropertyWithName :key],但是我无法找到的东西。
这会产生子问题A:如果您只拥有该属性的名称,如何测试属性设置器?
下一部分是我想根据其类型自动识别属性的地方。如果updateDict
和existingObj
都有一个用于键@“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对象同步,请分享!最后,结果是最重要的。
答案 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类。从运行时的角度来看,properties和general types有一个特定于实现的类型编码(例如方法参数/返回类型)。此类型编码对任何Objective-C对象使用单个编码(即@
),因此NSString
属性的类型编码与UIColor
属性的类型编码相同他们都是Objective-C课程。
如果你确实需要这个功能,另一种方法是处理你的类并添加一个类方法,该方法返回一个字典,其中包含在该类和超类中声明的每个属性(或你感兴趣的属性)的键和相应类型,或者某种描述语言。您必须自己完成此操作并依赖于运行时期间不可用的信息。