2010-11-23 3 views
0

Je suis nouveau dans le développement iPhone/Objective-C, je suis en train d'analyser XML avec succès avec NSXMLParser mais je ne peux pas obtenir des exceptions pour fonctionner correctement. J'aimerais utiliser des exceptions pour gérer le XML inattendu.NSAssert dans le délégué NSXMLParser ne pas être pris

Je suis enroulant le code pour créer l'objet NSXMLParser et l'envoi du setDelegate et analyser les messages à l'objet dans un bloc @try@catch, attraper @NSException.

Si je mets NSAssert(FALSE, @"error) à l'intérieur du bloc @try, l'exception est interceptée correctement. Si, cependant, j'ai un NSAssert échouer dans les appels de délégué (par exemple, didStartElement, didEndElement, foundCharacters), puis le programme meurt (dans iPhone Simulator, n'a pas encore essayé de périphérique). La trace de la pile du débogueur montre que l'assertion a été élevée dans une exception, mais elle ne ressort pas dans le code de niveau supérieur où le bloc @try se trouve autour de l'appel [parser parse]. Au lieu de cela, je reçois "Termination app en raison d'une exception non interceptée."

S'il vous plaît laissez-moi savoir si c'est un problème connu ou si je fais quelque chose de bête ici.

Merci - Alex

code pour rendre plus concrète; aucune tentative pour rendre ce code correct pour la mémoire/releases/etc.

@implementation XMLTester 

+(void)runXMLTester 
{ 
    BOOL success = FALSE; 
    XMLTester *tester = [[XMLTester alloc] init]; 
    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://api.wunderground.com/auto/wui/geo/WXCurrentObXML/index.xml?query=KSFO"]]; 
    NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data]; 
    [parser setDelegate:tester]; 
    @try { 
     //NSAssert(FALSE, @"error"); // this assertion works fine 
     success = [parser parse]; 
    } 
    @catch (NSException * e) { 
     success = FALSE; 
     NSLog(@"Exception caught %@: %@", [e name], [e reason]); 
    } 
    @finally { 
     NSLog(@"runXMLTester @finally block hit"); 
    } 
} 

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict 
{ 
    NSLog(@"Starting element %@", elementName); 
    NSAssert(FALSE, @"error"); // this assertion does not work - does not hit @try block around parse message 
} 
+0

Passer des exceptions via le code d'infrastructure est toujours une très mauvaise idée. Vous ne devriez pas déclencher d'exceptions dans vos méthodes de délégué. –

+0

Belle fuite de mémoire;) –

+0

Kevin - merci, je vais me méfier de ce modèle; tc - oui, le vrai code est plus prudent, mais j'ai besoin d'apprendre les bons modèles de gestion de la mémoire. – Alex

Répondre

0

According to Bill Bumgarner, attraper des exceptions dans l'iPhone Simulator ne fonctionne pas correctement. Votre meilleur pari est d'arrêter d'utiliser des exceptions ici, car ce n'est pas vraiment approprié de toute façon. Vous devriez appeler -[NSXMLParser abortParsing] à la place. Ne pas utiliser d'exceptions pour le contrôle de flux.

+0

Merci, très utile. J'aime utiliser des assertions, mais je crois qu'il faut utiliser seulement pour les choses qui seraient une erreur de programmeur - quelqu'un d'autre qui change son XML n'est pas vraiment une erreur de programmeur, donc mieux vaut traiter comme une erreur possible. Et ne devrait pas utiliser des exceptions ici pour les raisons spécifiques au cadre que vous avez données. Merci! – Alex

0

Ecriture d'exception-safe (refcounted) Obj-C code est un peu d'une douleur en particulier, les choses couramment utilisées comme Foo * foo = [[Foo alloc] init]; [foo doStuff]; [foo release]; foo = nil; fuiront et [foo lock]; [foo doStuff]; [foo unlock]; sera probablement deadlock. Vous pouvez atténuer le premier en autoreleasing toujours immédiatement (je le fais toujours pour éviter les fuites de mémoire lors de la refactorisation du code), sauf que vous ne pouvez pas libérer les pools autorelease. Ce dernier est difficile à éviter à moins que vous saupoudrez @ try/@ finalement partout.

En outre, je vivement recommandons breakpointing objc_exception_throw(). Parfois, Xcode semble manquer le lancer et vous déposer dans le débogueur quand abort() est appelé depuis uncaught_exception_handler() (ou quel que soit son nom) après que la pile ait été inutilement déroulée. Et plusieurs choses (notamment CoreAnimation) capturent, consignent et ignorent les exceptions, ce qui est pénible à déboguer à moins que vous ne regardiez le long.

Il y a un cas dans une application où j'ai utilisé une exception pour le flux de contrôle (je pense que je lui ai donné le nom "ControlThrow"); chaque fois que je frappe ce point d'arrêt, je suis tenté de le remplacer par un goto.

+0

Je suis d'accord de ne pas utiliser d'exceptions pour le contrôle de flux - ce n'était pas mon intention, la suggestion de Kevin d'utiliser abortParsing aide à rendre cela plus facile. Merci pour les autres suggestions ici. – Alex