2008-12-02 12 views
6

Я был бы признателен за некоторые отзывы о конкретном подходе, который я собираюсь использовать. Ниже приведен сценарий.Нечувствительность к регистру KVC в какао?

У меня есть объект (можно назвать его MObject), который имеет ряд свойств, скажем, x и y координат, высоты и ширины. Свойства называются в соответствии с рекомендациями KVC (MObject.x; MObject.height и т. Д.). Моя следующая задача - прочитать в XML-файле, который описывает этот MObject. К сожалению, элементы XML называются по-разному - X и Y, Height и Width (обратите внимание на заглавные буквы).

В идеале элементы XML будут соответствовать свойствам MObject. В этом случае, я мог бы использовать KVC и избежать целый сильный удар кода:

for (xmlProperty in xmlElement) 
{ 
    [MObject setValue:xmlProperty.value forKey:xmlProperty.name]. 
} 

Одним из способов приближения к этому было бы использовать клавиши регистронезависимых. С чего бы начать? Есть ли другие, лучшие решения?

Предложения очень ценятся.

ответ

3

Не переопределяйте -[NSObject valueForKey:] и -[NSObject setValue:forKey:], если вы можете вообще помочь.

Ваш лучший выбор - конвертировать ключи, которые вы получаете из 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]]. 
    } 
} 
3

Вы можете использовать NSString's lowercaseString для преобразования имени ключа XML в нижний регистр, если это помогает.

+0

Блестяще простое решение. Отлично сработано! – 2008-12-03 00:43:41

+0

Это сработает, я думаю, единственная проблема - соглашения об именах. – EightyEight 2008-12-03 00:48:52

1

Переопределение -valueForKey: и -setValue:forKey:.

Вы, вероятно, должны принимать только ключи (имена элементов/атрибутов), которые вы признаете, и звонить по super для других ключей.

3

Override -valueForUndefinedKey: и -setValue:forUndefinedKey:

Если вы нашли ключ с другой капитализации использовать его, в противном случае вызвать к super.

1

Так что я внедрил предложение Криса Хэнсона, и вот что я в итоге получил. Я положил это в мой класс Utils. Он хранит словарь для каждого класса, который мы просматриваем. Вероятно, он мог бы использовать небольшой рефакторинг, но до сих пор он работал очень хорошо.

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