Question

J'essaye d'analyser un XML que je reçois d'un service Web avec un NSXMLParserDelegate. La NSObject Je veux mettre les données dans (je vais juste l'appeler MyObject) a @propertys qui ne sont pas NSStrings (il y en a des NSDates, certains NSNumbers, et peut-être à un moment donné dans le futur certaines primitives).

Puisque le XML est une grosse chaîne, je reçois des erreurs et des plantages lorsque j'essaie de mettre directement les valeurs du XML dans mes propriétés (j'utilise [myObject setValue:currentElementValue forKey:elementName]; dans mon parser:didEndElement:..., qui fonctionne normalement bien - quand key est un NSString). Je ne m'attendais pas vraiment à ce que cela fonctionne, mais j'ai pensé que cela valait la peine.

La chose la plus simple à faire est simplement le code hardage de tout, donc si j'ai un gerne (@property (non atomique, fort) nsnumber * Âge; ' sur mon objet, quand je trouve le <age>25</age> une partie de mon XML, je fais MyObject.age = [NSNumber numberWithInt:[currentElementValue intValue]];. Le problème avec cela est qu'il est très rigide - j'aimerais que ce code soit plus dynamique que cela. Je ne veux pas avoir à savoir quelles sont toutes les propriétés de mon objet à l'avance.

J'ai également essayé de vérifier ce que le class de la propriété est, puis faire une conversion avant d'entrer une valeur (donc quelque chose comme [myObject setValue:[NSNumber numberWithInt:[currentElementValue intValue] forKey:elementName]; Si la propriété isKindOfClass:[NSNumber class]]. Le problème avec cela est que c'est la première fois que la propriété est utilisée, donc c'est nil, et n'a donc pas de classe. Donc, cette approche ne fonctionne pas non plus non plus.

Est-ce que je fais complètement mal? Il semble qu'il devrait être assez typique d'obtenir des données d'un XML et de les mettre en nonNSString Variables, mais je n'arrive pas à le faire fonctionner.

Si quelqu'un a besoin de voir plus de code pour mieux comprendre comment je suis configuré ou ce que j'ai déjà essayé, faites-le moi savoir.


Edit: J'ai trouvé un exemple rapide de ce que j'essaie de faire. Supposons que j'ai le XML suivant:

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

que je veux analyser une instance de MyObject (un NSObject sous-classe)

@interface MyObject: NSObject

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

@end

Et un deuxième XML

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

qui ira dans un cas de OtherObject (aussi NSObject sous-classe)

@interface OtherObject: NSObject

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

@end

Je veux créer un analyseur "modèle" (qui a @property (nonatomic, strong) NSObject *instance; et alors NSMutableString *currentElementValue comme un 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 ...
}
...

Ensuite, je sous-classe juste cet analyseur de "modèle" pour chacun de mes différents XML et écrase le init méthode pour que

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

ou

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

le cas échéant. J'ai beaucoup de services Web que j'appelle que je vais obtenir du XML structuré de la même manière, donc seulement avoir à changer 1 ligne dans les analyseurs pour chacun est quelque chose qui est très souhaitable. Avoir tout le reste du code d'analyse dans une seule classe "modèle" facilitera le maintien, la lecture et le débogage du code.

De toute évidence, le problème que j'ai est isKindOfClass n'accepte pas int, float, ou BOOL comme entrées. Y a-t-il quelque chose de similaire que je peux utiliser à la place?

Était-ce utile?

La solution

Le problème avec cela est que c'est la première fois que la propriété est utilisée, il est donc nulle et n'a donc pas de classe.

Objective-C permet de Propriétés de la classe de requête au moment de l'exécution, donc introspecter le type de propriété et utiliser une transformation TRNS appropriée est une façon de faire.

Vous pouvez en savoir plus sur l'exécution sur le blog de Mike Ash ou voir Objectif C introspection / réflexion.

Cependant, Ce problème spécifique a été rencontré par de nombreuses autres personnes, il y a donc pas mal de solutions: comme dit dans bibliothèque de services de repos les plus matures iOS RESTKIT est un bon exemple d'une telle bibliothèque; MagicRecord en est un autre.

Vous pouvez facilement trouver quelques bibliothèques supplémentaires à consulter avant de décider d'implémenter votre propre solution.

Autres conseils

Bien sûr, je pouvais simplement remplacer le init méthode de MyObject Pour alloc-init toutes mes propriétés aux valeurs vides, ce qui devrait résoudre le nil Problème que j'ai fait référence dans mon OP, mais cela semble vraiment hacky. C'est peut-être la seule option cependant.


Edit: Cette approche s'effondre totalement avec l'exemple de l'édition de l'OP. KVC tournera ints, floatle sable BOOLest tout à NSNumbers, sans aucun moyen de savoir ce qu'ils à l'origine. Ce qui signifie que je ne pourrai pas appeler [currentElementValue intValue], [currentElementValue floatValue], ou [currentElementValue boolValue] le cas échéant.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top