如何测试属性的存在和类型基于NSString类型键? [英] How to test property existence and type based on NSString typed key?

查看:190
本文介绍了如何测试属性的存在和类型基于NSString类型键?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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


  1. existingObj updateDict

  2. 不是 updateDict 的所有属性都可用 extistingObj

  3. 并非所有类型的 existingObj JSON反序列化属性。 (某些字符串可能需要自定义的Objective-C包装器)。

  4. updateDict 可能包含未初始化的键值$ c> nil )in existingObj

这意味着,在迭代更新的字典时,必须有一些属性的来回测试。首先我要测试 updateDict 的属性是否存在于 existingObj 中,然后使用KVC设置值,例如所以:

  //键是NSString @displayName
if([existingObj respondingToSelector:NSSelectorFromString(key)){
[existingObj setValue:[updateDict objectForKey:key] forKey:key];
}

虽然这部分工作,我不喜欢这样的事实,实际测试 displayName 作为getter,而我将要调用 setDisplayName: setter(间接通过KVC) 。我想要的是像[existingObj hasWritablePropertyWithName :key],但这样做的东西,我找不到。



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

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

  if([existingObj typeOfSelector:sel] == [[updateDict objectForKey:key] class]){
//正常分配
} else {
//执行自定义分配
}

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



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



我想是的。我认为这必须是一个已经在这里的东西的欺骗,但我找不到它。也许你们可以吗?

Cheers,EP。



如果你有更好的方法来同步自定义Objective-C对象和反序列化的JSON对象,请分享!

解决方案

如果你想查询一个对象是否有给定KVC的setter您需要检查它是否响应一个名为 setKey:的选择器方法的键 (以 set 开头,大写键中的第一个字符,添加一个结尾冒号)。例如,

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

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

两个备注:




  • 即使属性可能具有不遵循上述模式的名称的setter,它们也不会与KVC兼容,因此可以安全地检查设置< Key>:,因为您使用KVC设置相应的值。


  • KVC不使用setter方法只要。如果没有找到setter方法,它会检查类是否允许直接访问实例变量,如果是,则使用instance变量设置值。此外,如果没有找到setter方法或实例变量,它会发送 -setValue:forUndefinedKey:给接收者,它的类可能已经覆盖了抛出异常的标准实现。这在键值编码编程指南。那么,如果你总是使用属性,检查setter方法应该是安全的。




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



如果你确实需要这个功能,一个替代方法是处理你的类,并添加一个类方法,返回一个字典的键和相应的类型为每个属性(或你感兴趣的)在该类和超类中声明,或者也许是某种描述语言。你必须自己这样做,并依赖运行时不可用的信息。


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:

  1. Not all properties of the existingObj are present in the updateDict
  2. Not all properties of the updateDict are available in the extistingObj.
  3. Not all types of existingObj's properties match the JSON deserialized properties. (some strings may need a custom Objective-C wrapper).
  4. updateDict may contain values for keys that are uninitialized (nil) in existingObj.

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.

解决方案

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 called setKey: (starts with set, capitalise the first character in key, add a trailing colon). For instance,

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];
}

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 an NSString property is the same as the type encoding of a UIColor 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.

这篇关于如何测试属性的存在和类型基于NSString类型键?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆