如何根据 NSString 类型键测试属性是否存在和类型?
在我寻求更新 iOS 项目中的核心数据模型时,我在服务器上查询 JSON 对象,这些对象在某种程度上与我的模型的托管实体相对应。我追求的最终结果是从 JSON 输出获得可靠的更新解决方案。
对于本问题中的示例,我将命名核心数据管理对象 existingObj
和传入的 JSON 反序列化字典 updateDict
。棘手的部分是处理这些事实:
- 并非
existingObj
的所有属性都存在于updateDict
中, - 并非
updateDict
的所有属性都可用existingObj
。 - 并非所有类型的
existingObj
属性都与 JSON 反序列化属性匹配。 (某些字符串可能需要自定义 Objective-C 包装器)。 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
作为 getter,而我即将调用 setDisplayName:
setter(间接通过 KVC)。我宁愿是类似 [existingObj hasWritablePropertyWithName:key] 的东西,但我找不到这样做的东西。
这构成了子问题 A:如果只有属性的名称,如何测试属性设置器?
下一部分是我想根据属性类型自动进行属性识别。如果 updateDict 和 existingObj 都有一个 NSString 键 @"displayName",则设置新值很容易。但是,如果 updateDict 包含键 @"color" 的 NSString,即 @"niceShadeOfGreen",我想将其转换为正确的 UIColor 实例。但是如何测试 existingObj
中接收属性的类型,以便我知道何时转换值以及何时简单分配?我希望得到类似 typeOfSelector: 的东西,
if ([existingObj typeOfSelector:sel] == [[updateDict objectForKey:key] class]) {
// regular assignment
} else {
// perform custom assignment
}
当然这是假代码。我不能依赖于测试 existingObj
属性值的类型,因为它可能是统一的或 nil
。
子问题 B:如果只有属性的名称,如何测试属性的类型?
我想就是这样。我想这一定是这里已经存在的东西的骗局,但我找不到它。也许你们可以?
干杯,EP。
PS 如果您有更好的方法将自定义 Objective-C 对象同步到反序列化 JSON 对象,请分享!最后,结果才是最重要的。
In my quest to update a Core Data model within my iOS project, I'm querying a server for JSON objects that correspond - to some extent - with the managed entities of my model. The end result I'm striving for is a reliable update solution from JSON output.
For the examples in this question, I'll name the core data managed object existingObj
and the incoming JSON deserialized dictionary updateDict
. The tricky part is dealing with these facts:
- Not all properties of the
existingObj
are present in theupdateDict
- Not all properties of the
updateDict
are available in theextistingObj
. - Not all types of
existingObj
's properties match the JSON deserialized properties. (some strings may need a custom Objective-C wrapper). updateDict
may contain values for keys that are uninitialized (nil
) inexistingObj
.
This means that while iterating through the updated dictionaries, there has to be some testing of properties back and forth. First I have to test whether the properties of the updateDict
exist in existingObj
, then I set the value using KVC, like so:
// key is an NSString, e.g. @"displayName"
if ([existingObj respondsToSelector:NSSelectorFromString(key)) {
[existingObj setValue:[updateDict objectForKey:key] forKey:key];
}
Although this part works, I don't like the fact that I'm actually testing for displayName
as a getter, while I'm about to call the setDisplayName:
setter (indirectly via KVC). What I'd rather to is something like [existingObj hasWritablePropertyWithName:key], but something that does this I can't find.
This makes for subquestion A: How does one test for a property setter, if you only have the property's name?
The next part is where I'd like to automate the property identification based on their types. If both the updateDict
and the existingObj
have an NSString for key @"displayName", setting the new value is easy. However, if the updateDict
contains an NSString for key @"color" that is @"niceShadeOfGreen", I'd like to transform this into the right UIColor instance. But how do I test the type of the receiving property in existingObj
so I know when to convert values and when to simply assign? I was hoping for something along the lines of typeOfSelector:
if ([existingObj typeOfSelector:sel] == [[updateDict objectForKey:key] class]) {
// regular assignment
} else {
// perform custom assignment
}
Of course this is boguscode. I can't rely on testing the type of the existingObj
-property's value, for it may be unitialized or nil
.
Subquestion B: How does one test for the type of a property, if you only have the property's name?
I guess that's it. I figured this must be a dupe of something that's already on here, but I couldn't find it. Maybe you guys can?
Cheers, EP.
P.S. If you'd have a better way to synchronize custom Objective-C objects to deserialized JSON objects, please do share! In the end, the result is what counts.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果你想查询一个对象是否有一个名为
key
的给定KVC键的setter,它对应于一个声明的属性,你需要检查它是否响应一个名为setKey:<的选择器方法/code> (以
set
开头,将key
中的第一个字符大写,添加尾随冒号)。例如,有两点注释:
尽管属性的 setter 名称可能不遵循上述模式,但它们不符合 KVC 标准,因此检查
set:< /code> 因为您使用 KVC 设置相应的值。
KVC 不仅仅使用 setter 方法。如果它没有找到 setter 方法,它会检查该类是否允许直接访问实例变量,如果是,则使用实例变量来设置值。此外,如果没有找到 setter 方法或实例变量,它会将
-setValue:forUndefinedKey:
发送到接收者,接收者的类可能会覆盖引发异常的标准实现。 键值编码编程指南。也就是说,如果您总是使用属性,检查 setter 方法应该是安全的。至于你的第二个问题,不可能查询运行时来了解属性的实际 Objective-C 类。从运行时的角度来看,属性 和 一般类型(例如方法参数/返回类型)。这种类型编码对任何 Objective-C 对象都使用单一编码(即
@
),因此NSString
属性的类型编码与@
属性的类型编码相同。 code>UIColor 属性,因为它们都是 Objective-C 类。如果您确实需要此功能,一种替代方法是处理您的类并添加一个类方法,该方法返回一个字典,其中包含该类和超类中声明的每个属性(或您感兴趣的属性)的键和相应类型,或者也许某种描述语言。您必须自己执行此操作并依赖运行时不可用的信息。
If you want to query whether an object has a setter for a given KVC key called
key
which corresponds to a declared property, you need to check whether it responds to a selector method calledsetKey:
(starts withset
, capitalise the first character inkey
, add a trailing colon). For instance,Two remarks:
Even though properties can have setters with names that do not follow the pattern described above, they wouldn’t be KVC compliant, so it is safe to check for
set<Key>:
since you’re using KVC to set the corresponding value.KVC doesn’t use the setter method only. If it doesn’t find a setter method, it checks whether the class allows direct access to instance variables and, if so, use the instance variable to set the value. Also, if no setter method or instance variable is found, it sends
-setValue:forUndefinedKey:
to the receiver, whose class might have overridden the standard implementation that throws an exception. This is described in the Key-Value Coding Programming Guide.That said, if you’re always using properties, checking for the setter method should be safe.As for your second question, it is not possible to query the runtime to know the actual Objective-C class of a property. From the runtime perspective, there’s an implementation specific type encoding for properties and general types (such as method parameters/return types). This type encoding uses a single encoding (namely
@
) for any Objective-C object, so the type encoding of anNSString
property is the same as the type encoding of aUIColor
property since they’re both Objective-C classes.If you do need this functionality, one alternative is to process your classes and add a class method that returns a dictionary with keys and corresponding types for every property (or the ones you’re interested in) declared in that class and superclasses, or maybe some sort of description language. You’d have to do this on your own and rely on information not available during runtime.