2008-12-02 14 views
6

Ich hätte gerne ein Feedback zu einem bestimmten Ansatz, den ich mir vorstellen möchte. Das Szenario ist unten.Case-insensitive KVC in Kakao?

Ich habe ein Objekt (nennen wir es MObject), das eine Reihe von Eigenschaften hat, sagen wir x und y Koordinaten, Höhe und Breite. Die Eigenschaften werden nach den KVC-Richtlinien benannt (MObject.x; MObject.height usw.). Meine nächste Aufgabe ist das Einlesen einer XML-Datei, die dieses MObject beschreibt. Leider sind die XML-Elemente unterschiedlich benannt - X und Y, Höhe und Breite (beachten Sie die Groß-/Kleinschreibung).

Idealerweise stimmen die XML-Elemente mit den Eigenschaften von MObject überein. In diesem Fall könnte ich KVC verwenden und ein ganzes Gleichgewicht gerät Code vermeiden:

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

Eine Möglichkeit, dies zu nähern wäre die Verwendung von Groß- und Kleinschreibung Schlüsseln zu machen. Wo würde ich damit anfangen? Gibt es noch andere, bessere Lösungen?

Vorschläge sehr geschätzt.

Antwort

3

Überschreiben Sie -[NSObject valueForKey:] und -[NSObject setValue:forKey:] nicht, wenn Sie überhaupt helfen können.

Ihre beste Wette wäre, die Schlüssel, die Sie aus der XML-Datei erhalten, im laufenden Betrieb zu konvertieren. Verwenden Sie eine separate Methode für die Konvertierung, und Sie können auch einen Cache mit Namen für Eigenschaftsschlüssel verwalten, sodass Sie jede Konvertierung nur einmal durchführen müssen.

- (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

Sie können lowercaseString von NSString verwenden, um den XML-Schlüsselnamen in Kleinbuchstaben umzuwandeln, wenn das hilft.

+0

Brillant einfache Lösung. Gut gemacht! –

+0

Das würde funktionieren, ich denke, das einzige Problem ist die Namenskonventionen. – EightyEight

1

Übersteuern -valueForKey: und -setValue:forKey:.

Sie sollten wahrscheinlich nur Schlüssel (Element-/Attributnamen), die Sie erkennen, akzeptieren und bis zu super für andere Schlüssel aufrufen.

3

Aufschalten -valueForUndefinedKey: und -setValue:forUndefinedKey:

Wenn Sie einen Schlüssel mit einer anderen Aktivierung verwenden Sie es finden, rufen Sie sonst zu super auf.

1

Also habe ich den Vorschlag von Chris Hanson umgesetzt und hier ist, was ich am Ende hatte. Ich lege das in meine Utils-Klasse. Es enthält ein Wörterbuch für jede Klasse, die wir suchen. Es könnte wahrscheinlich ein wenig Refactoring verwenden, aber es hat für mich bisher sehr gut funktioniert.

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

Vergessen Sie auch nicht #import