Frage

Ich versuche durch ein XML zu analysieren, den ich von einem Webservice mit einem bekomme NSXMLParserDelegate. Das NSObject Ich möchte die Daten einsetzen (ich werde sie einfach nennen MyObject) hat @propertys, das nicht sind NSStrings (es gibt einige NSDateS, einige NSNumberS und vielleicht irgendwann in Zukunft einige Primitive).

Da der XML alles eine große Zeichenfolge ist, bekomme ich Fehler und stürze, wenn ich versuche, die Werte einfach direkt aus dem XML in meine Eigenschaften einzulegen (ich verwende [myObject setValue:currentElementValue forKey:elementName]; in meinem parser:didEndElement:..., was normalerweise gut funktioniert - wann key ist ein NSString). Ich hatte nicht wirklich erwartet, dass dies funktioniert, aber ich dachte, es war einen Schuss wert.

Das einfachste, was zu tun ist, ist nur Hardcode zu tun. auf meinem Objekt, wenn ich das finde <age>25</age> Teil meines XML, das tue ich MyObject.age = [NSNumber numberWithInt:[currentElementValue intValue]];. Das Problem dabei ist, dass es sehr starr ist - ich möchte, dass dieser Code dynamischer ist. Ich möchte nicht wissen, was alle Eigenschaften meines Objekts im Voraus sind.

Ich habe auch versucht zu überprüfen, was die class der Eigenschaft ist und dann eine gewisse Konvertierung vor dem Eingeben eines Wertes (so etwas wie [myObject setValue:[NSNumber numberWithInt:[currentElementValue intValue] forKey:elementName]; Wenn die Eigenschaft isKindOfClass:[NSNumber class]]. Das Problem dabei ist, dass dies das erste Mal ist, dass Eigenschaft verwendet wird, so dass es so ist nil, und hat daher keine Klasse. Dieser Ansatz funktioniert also auch nicht wirklich.

Mache ich das völlig falsch? Es scheint, als sollte es ziemlich typisch sein, Daten von einem XML zu erhalten und sie in Nichts zu setzenNSString Variablen, aber ich kann es nicht zum Laufen bringen.

Wenn jemand mehr Code sehen muss, um ein besseres Verständnis dafür zu erhalten, wie ich dies eingerichtet habe oder was ich bereits ausprobiert habe, lassen Sie es mich wissen.


EDIT: Ich habe ein kurzes Beispiel dafür gefunden, was ich versuche zu tun. Angenommen, ich habe das folgende XML:

<Object>
    <ITEM_NUMBER>4</ITEM_NUMBER>
    <IS_AWESOME>YES</IS_AWESOME>
    <AWESOMENESS>9000.1</AWESOMENESS>
</Object>

dass ich in eine Instanz von analysieren möchte MyObject (ein NSObject Unterklasse)

@interface MyObject: NSObject

@property (nonatomic, assign) int ITEM_NUMBER;
@property (nonatomic, assign) BOOL IS_AWESOME;
@property (nonatomic, assign) float AWESOMENESS;

@end

Und eine zweite XML

<OtherObject>
    <PRICE>4.99</PRICE>
    <QUANTITY>5</QUANTITY>
    <FOR_RESALE>NO</FOR_RESALE>
</OtherObject>

das wird in eine Instanz von gehen OtherObject (Auch NSObject Unterklasse)

@interface OtherObject: NSObject

@property (nonatomic, assign) int QUANTITY;
@property (nonatomic, assign) BOOL FOR_RESALE;
@property (nonatomic, assign) float PRICE;

@end

Ich möchte einen "Vorlage" -Parser erstellen (der hat @property (nonatomic, strong) NSObject *instance; und dann NSMutableString *currentElementValue als Ivar)

...
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
    [currentElementValue setString:string];
}

- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    if ([[self.instance valueForKey:elementName] isKindOfClass:int])
    {
        [self.instance setValue:[currentElementValue intValue] forKey:elementName];
    }
    else if ([[self.instance valueForKey:elementName] isKindOfClass:float])
    {
        [self.instance setValue:[currentElementValue floatValue] forKey:elementName];
    }
    else if ([[self.instance valueForKey:elementName] isKindOfClass:BOOL])
    {
        [self.instance setValue:[currentElementValue boolValue] forKey:elementName];
    }
    else if ...
}
...

Dann unterklasse ich diesen "Vorlage" -Parser für jeden meiner verschiedenen XMLs und überschreibe das init Methode so

self.instance = [[MyObject alloc] init];

oder

self.instance = [[OtherObject alloc] init];

wie angemessen. Ich habe viele Webservices, die ich nenne, die ich ähnlich strukturiert habe. Wenn Sie den Rest des Parser -Codes in einer einzigen "Vorlage" -Klasse haben, wird das Wartung, Lesen und Debuggen des Codes so viel einfacher.

Offensichtlich ist das Problem, das ich habe isKindOfClass akzeptiert nicht int, float, oder BOOL als Eingänge. Gibt es etwas Ähnliches, das ich stattdessen verwenden kann?

War es hilfreich?

Lösung

Das Problem dabei ist, dass dies das erste Mal ist, dass Eigenschaft verwendet wird, so dass sie Null ist und daher keine Klasse hat.

Objective-C erlaubt zu Abfragemeigenschaften zur Laufzeit, Die Eigenschaftstyp und die Verwendung einer geeigneten TRNSformation sind also eine Möglichkeit.

Sie können mehr über die Laufzeit lesen in Mike Ashs Blog oder sehen Objektive C -Selbstbekämpfung/Reflexion.

Jedoch, Dieses spezifische Problem wurde von vielen anderen Menschen angetroffen, Es gibt also einige Lösungen: wie in iOS reifer REST -Service -Bibliothek Restkit ist ein gutes Beispiel für eine solche Bibliothek; MagicRecord ist ein anderer.

Sie können leicht ein paar weitere Bibliotheken finden, die Sie auschecken können, bevor Sie sich für die Implementierung Ihrer eigenen Lösung entscheiden.

Andere Tipps

Natürlich konnte ich das einfach außer Kraft setzen init Methode von MyObject Alloc-initiert alle meine Eigenschaften zu leeren Werten, die die lösen sollten nil Problem, auf das ich mich in meinem OP verwiesen habe, aber das fühlt sich einfach wirklich hacky an. Es kann jedoch die einzige Option sein.


Bearbeiten: Dieser Ansatz fällt mit dem Beispiel in der Bearbeitung im OP völlig auseinander. KVC wird sich drehen ints, floats, und BOOLs alle zu NSNumberS, ohne zu wissen, was sie ursprünglich wo. Das heißt, ich werde nicht anrufen können [currentElementValue intValue], [currentElementValue floatValue], oder [currentElementValue boolValue] wie angemessen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top