2009-08-15 11 views
0

J'ai besoin d'analyser un enregistrement XML qui représente une QuizQuestion. L'attribut "type" indique le type de question. J'ai alors besoin de créer une sous-classe appropriée de QuizQuestion basée sur le type de question. Le code suivant fonctionne (déclarations de libération [auto] omis pour plus de clarté):OO Conception Objective-C avec analyse XML

QuizQuestion *question = [[QuizQuestion alloc] initWithXMLString:xml]; 
if([ [question type] isEqualToString:@"multipleChoiceQuestion"]) { 
    [myQuestions addObject:[[MultipleChoiceQuizQuestion alloc] initWithXMLString:xml]; 
} 

//QuizQuestion.m 
-(id)initWithXMLString:(NSString*)xml { 
    self.type = ...// parse "type" attribute from xml 
    // parse the rest of the xml 
} 

//MultipleChoiceQuizQuestion.m 
-(id)initWithXMLString:(NSString*)xml { 
    if(self= [super initWithXMLString:xml]) { 
     // multiple-choice stuff 
    } 
} 

Bien sûr, cela signifie que le XML est analysé deux fois: une fois pour connaître le type de QuizQuestion, et une fois que lorsque le QuizQuestion approprié est initialisé.

Pour éviter l'analyse syntaxique du XML deux fois, j'ai essayé l'approche suivante:

// MultipleChoiceQuizQuestion.m 
-(id)initWithQuizRecord:(QuizQuestion*)record { 
    self=record; // record has already parsed the "type" and other parameters 
    // multiple-choice stuff 
} 

Cependant, cela ne fonctionne pas en raison de la cession « auto = enregistrement »; à chaque fois que MultipleChoiceQuizQuestion essaie d'appeler une méthode d'instance, il essaie d'appeler la méthode sur la classe QuizQuestion à la place.

Quelqu'un peut-il me dire la bonne approche pour analyser XML dans la sous-classe appropriée lorsque la classe parente doit être initialisée pour savoir quelle sous-classe est appropriée?

Répondre

1

Je suppose que vous utilisez NSXMLParser pour analyser la chaîne XML et utiliser certains des événements qu'il déclenche pour analyser la source XML. Dans MultipleChoiceQuizQuestion, vous pouvez remplacer les méthodes de délégué de NSXMLParser, comme:

- (void)parser:(NSXMLParser *)parser 
    didStartElement:(NSString *)elementName 
    namespaceURI:(NSString *)namespaceURI 
    qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict 
{ 
    [super parser:parser 
     didStartElement:elementName 
     namespaceURI:namespaceURI 
     qualifiedName:qName attributes:attributeDict] 

    // Multiple-choice specific stuff goes here. 
} 

Ensuite, appelez self = [super initWithXMLString:xml] comme suggéré.

0

Si vous voulez retourner une autre instance dans votre init, vous devez faire ceci:

-(id)init { 

    if (iNeedToBeADifferentClass) { 
     [self release]; 
     return [[MyOtherClass alloc] init]; 
    } else { 
     if (self = [super init]) { 
       // normal init stuff 
     } 
     return self; 
    } 
} 

Avec cela, vous pouvez analyser le XML dans QuizQuestion, init le MultipleChoiceQuizQuestion avec les valeurs analysées et extra Morceau de XML que seul MultipleChoiceQuizQuestion doit analyser.

Sinon, vous pouvez utiliser des classes de fabrique ou un autre modèle. Tout dépend de la structure de votre XML, cependant - si votre XML est structuré avec l'analyse, il sera beaucoup plus facile de le faire dans le code.

+0

Ce code me semble très approximatif. [auto-libération] est à la fois dangereux et cruel, car vous forcez votre objet à se suicider. Cela semble dangereux puisque vous finissez par exécuter du code dans une instance de classe qui a été distribuée. Blague à part, une meilleure façon d'obtenir des fonctionnalités similaires pourrait être d'utiliser une fonction d'usine. – Tyler

+0

Il existe des cas (rares) où cette méthodologie est valide et utilisée (par exemple NSManagedObjectContext renvoie une instance de classe différente de initWithEntity: insertIntoManagedObjectContext :), mais je suis d'accord que c'est normalement une mauvaise idée. [auto autorelease] serait plus sûr, cependant. – iKenndac