2010-11-23 6 views
0

Ich bin neu in iPhone/Objective-C-Entwicklung, ich bin erfolgreich Parsing XML mit NSXMLParser, aber ich kann nicht Ausnahmen erhalten, um ordnungsgemäß zu funktionieren. Ich möchte Ausnahmen verwenden, um mit unerwartetem XML umzugehen.NSAsssert in NSXMLParser Delegat nicht gefangen

Ich Umwickeln Sie den Code für das NSXMLParser Objekt erstellt und in einem @try@catch Block die setDelegate und analysieren Nachrichten an das Objekt zu senden, fangen @NSException.

Wenn ich NSAssert(FALSE, @"error) in den @try Block setzen, wird die Ausnahme richtig gefangen. Wenn ich jedoch einen NSAssert Fehler innerhalb der Delegiertenanrufe (z. B. didStartElement, didEndElement, foundCharacters) habe, dann stirbt das Programm (im iPhone Simulator, Gerät noch nicht ausprobiert). Die Debugger-Stack-Ablaufverfolgung zeigt, dass die Assertion in eine Ausnahme ausgelöst wurde, aber nicht in den Code der obersten Ebene zurückversetzt wird, in dem sich der @try-Block um den [parser parse]-Nachrichtenaufruf befindet. Stattdessen bekomme ich "Beenden der App aufgrund einer nicht abgefangenen Ausnahme".

Bitte lassen Sie mich wissen, wenn dies ein bekanntes Problem ist oder wenn ich hier etwas Dummes mache.

Danke - Alex

Einige Code konkreter zu machen; Kein Versuch, diesen Code für Speicher/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

Das Übergeben von Ausnahmen durch Framework-Code ist immer eine wirklich schlechte Idee. Sie sollten in Ihren Delegatmethoden keine Ausnahmen auslösen. –

+0

Schöne Speicherleck;) –

+0

Kevin - danke, ich werde vorsichtig sein, dieses Muster; tc - Ja, der echte Code ist vorsichtiger, aber ich muss richtige Speicherverwaltungsmuster lernen. – Alex

Antwort

0

According to Bill Bumgarner, Ausnahmen im iPhone-Simulator korrekt funktioniert nicht. Ihre beste Wette ist, Ausnahmen hier zu stoppen, da es sowieso nicht wirklich angebracht ist. Sie sollten stattdessen -[NSXMLParser abortParsing] anrufen.

+0

Danke, sehr hilfreich. Ich mag Assertionen verwenden, aber glaube nur für Dinge, die Programmierer Fehler sein würden - jemand anderes ändern ihre XML ist nicht wirklich Programmierer Fehler so am besten zu behandeln als ein echter Fehler. Und sollten Sie hier keine Ausnahmen für die Framework-spezifischen Gründe verwenden, die Sie angegeben haben. Vielen Dank! – Alex

0

Verwenden Sie keine Ausnahmen für die Flusssteuerung. Schreiben Ausnahme-Safe (refcounted) Obj-C-Code ist ein bisschen Schmerz — insbesondere häufig verwendeten Sachen wie Foo * foo = [[Foo alloc] init]; [foo doStuff]; [foo release]; foo = nil; wird undicht und [foo lock]; [foo doStuff]; [foo unlock]; wird wahrscheinlich Deadlock. Sie können die erste durch die automatische Autorelease sofort abmildern (ich tue immer, um Speicherlecks beim Refactoring zu vermeiden), außer Sie können Autorelease-Pools nicht automatisch freigeben. Letzteres ist schwer zu vermeiden, es sei denn, Sie streuen @ try/@ schließlich überall.

Zusätzlich ich stark empfehlen breakpointing objc_exception_throw(). Manchmal scheint Xcode den Wurf zu verpassen und lässt Sie in den Debugger fallen, wenn abort() von uncaught_exception_handler() (oder wie auch immer er aufgerufen wird) aufgerufen wird, nachdem der Stapel nicht hilfreich abgewickelt wurde. Und einige Dinge (insbesondere CoreAnimation) fangen Ausnahmen auf, loggen sie auf und ignorieren sie auf andere Weise, was ein mühsames Debugging ist, solange Sie nicht lange aufpassen.

Es gibt einen Fall in einer App, wo ich eine Ausnahme für den Kontrollfluss verwendet habe (ich glaube, ich gab ihm den Namen "ControlThrow"); Jedes Mal, wenn ich diesen Haltepunkt erreiche, bin ich versucht, ihn durch einen Goto zu ersetzen.

+0

Ich stimme zu, keine Ausnahmen für die Flusskontrolle zu verwenden - das war nicht meine Absicht, Kevins Vorschlag, abortParsing zu verwenden, macht das leichter. Danke für die anderen Vorschläge hier. – Alex