最好的选择是即时转换从 XML 文件获得的密钥。 使用单独的方法进行转换,您还可以维护名称到属性键的缓存,因此每个转换只需执行一次。
- (NSString *)keyForName:(NSString *)name {
// _nameToKeyCache is an NSMutableDictionary that caches the key
// generated for a given name so it's only generated once per name
NSString *key = [_nameToKeyCache objectForKey:name];
if (key == nil) {
// ...generate key...
[_nameToKeyCache setObject:key forKey:name];
}
return key;
}
- (void)foo:xmlElement {
for (xmlProperty in xmlElement) {
[myObject setValue:xmlProperty.value forKey:[self keyForName:xmlProperty.name]].
}
}
Don't override -[NSObject valueForKey:] and -[NSObject setValue:forKey:] if you can at all help it.
Your best bet would be to convert the keys you get from the XML file on the fly. Use a separate method to do the conversion and you can also maintain a cache of names to property keys, so you only need to do each conversion once.
- (NSString *)keyForName:(NSString *)name {
// _nameToKeyCache is an NSMutableDictionary that caches the key
// generated for a given name so it's only generated once per name
NSString *key = [_nameToKeyCache objectForKey:name];
if (key == nil) {
// ...generate key...
[_nameToKeyCache setObject:key forKey:name];
}
return key;
}
- (void)foo:xmlElement {
for (xmlProperty in xmlElement) {
[myObject setValue:xmlProperty.value forKey:[self keyForName:xmlProperty.name]].
}
}
static NSMutableDictionary *keyCache;
+ (NSString *)keyForClass:(Class)klass column:(NSString *)column {
if (!keyCache) { keyCache = [NSMutableDictionary dictionary]; }
NSString *className = NSStringFromClass(klass);
NSMutableDictionary *tableKeyCache = [keyCache objectForKey:className];
if (!tableKeyCache) {
tableKeyCache = [NSMutableDictionary dictionary];
unsigned int numMethods = 0;
Method *methods = class_copyMethodList(klass, &numMethods);
NSMutableArray * selectors = [NSMutableArray array];
for (int i = 0; i < numMethods; ++i) {
SEL selector = method_getName(methods[i]);
[selectors addObject:NSStringFromSelector(selector)];
}
[tableKeyCache setValue:selectors forKey:@"allSelectors"];
free(methods);
[keyCache setValue:tableKeyCache forKey:className];
}
NSString *keyToReturn = [tableKeyCache valueForKey:column];
if (!keyToReturn) {
for (NSString *columnKey in [tableKeyCache valueForKey:@"allSelectors"]) {
if ( [column caseInsensitiveCompare:columnKey] == NSOrderedSame) {
[tableKeyCache setValue:columnKey forKey:column];
keyToReturn = columnKey;
break;
}
}
}
if (!keyToReturn) { // Taking a guess here...
NSLog(@"Selector not found for %@: %@ ", className, column);
keyToReturn = [Utils keyForClass:[klass superclass] column:column];
}
return keyToReturn;
}
So I implemented Chris Hanson's suggestion and here's what I ended up with. I put this in my Utils class. It keeps a dictionary for each class that we lookup. It could probably use a little refactoring but it has worked very well for me so far.
static NSMutableDictionary *keyCache;
+ (NSString *)keyForClass:(Class)klass column:(NSString *)column {
if (!keyCache) { keyCache = [NSMutableDictionary dictionary]; }
NSString *className = NSStringFromClass(klass);
NSMutableDictionary *tableKeyCache = [keyCache objectForKey:className];
if (!tableKeyCache) {
tableKeyCache = [NSMutableDictionary dictionary];
unsigned int numMethods = 0;
Method *methods = class_copyMethodList(klass, &numMethods);
NSMutableArray * selectors = [NSMutableArray array];
for (int i = 0; i < numMethods; ++i) {
SEL selector = method_getName(methods[i]);
[selectors addObject:NSStringFromSelector(selector)];
}
[tableKeyCache setValue:selectors forKey:@"allSelectors"];
free(methods);
[keyCache setValue:tableKeyCache forKey:className];
}
NSString *keyToReturn = [tableKeyCache valueForKey:column];
if (!keyToReturn) {
for (NSString *columnKey in [tableKeyCache valueForKey:@"allSelectors"]) {
if ( [column caseInsensitiveCompare:columnKey] == NSOrderedSame) {
[tableKeyCache setValue:columnKey forKey:column];
keyToReturn = columnKey;
break;
}
}
}
if (!keyToReturn) { // Taking a guess here...
NSLog(@"Selector not found for %@: %@ ", className, column);
keyToReturn = [Utils keyForClass:[klass superclass] column:column];
}
return keyToReturn;
}
发布评论
评论(5)
如果可以的话,不要覆盖
-[NSObject valueForKey:]
和-[NSObject setValue:forKey:]
。最好的选择是即时转换从 XML 文件获得的密钥。 使用单独的方法进行转换,您还可以维护名称到属性键的缓存,因此每个转换只需执行一次。
Don't override
-[NSObject valueForKey:]
and-[NSObject setValue:forKey:]
if you can at all help it.Your best bet would be to convert the keys you get from the XML file on the fly. Use a separate method to do the conversion and you can also maintain a cache of names to property keys, so you only need to do each conversion once.
如果有帮助的话,您可以使用 NSString 的
lowercaseString
将 XML 键名称转换为小写。You can use NSString's
lowercaseString
to convert the XML key name to lowercase, if that helps.覆盖
-valueForUndefinedKey:
和-setValue:forUndefineKey:
如果您发现具有不同大小写的键,请使用它,否则调用
super
。Override
-valueForUndefinedKey:
and-setValue:forUndefinedKey:
If you find a key with a different capitalization use it, otherwise call up to
super
.覆盖
-valueForKey:
和-setValue:forKey:
。您可能应该只接受您识别的键(元素/属性名称),并为其他键调用
super
。Override
-valueForKey:
and-setValue:forKey:
.You should probably only accept keys (element/attribute names) you recognize, and call up to
super
for other keys.所以我实施了克里斯·汉森的建议,这就是我的最终结果。 我把它放在我的 Utils 类中。 它为我们查找的每个类保留一个字典。 它可能需要一些重构,但到目前为止对我来说效果很好。
So I implemented Chris Hanson's suggestion and here's what I ended up with. I put this in my Utils class. It keeps a dictionary for each class that we lookup. It could probably use a little refactoring but it has worked very well for me so far.