2010-11-23 4 views
0

iPhone/Objective-C 개발을 처음 사용하여 NSXMLParser을 사용하여 XML을 성공적으로 파싱했으나 예외가 올바르게 작동하지 않습니다. 예기치 않은 XML을 처리하기 위해 예외를 사용하고 싶습니다.NSXMLParser 대리인의 NSAssert가 캐치되지 않았습니다.

은 내가 NSXMLParser 객체를 생성하고 setDelegate를 보내고 구문 분석 메시지를 객체에 @try@catch 블록 내부 @NSException을 잡기위한 코드를 포장하고있다.

NSAssert(FALSE, @"error)을 @try 블록에 넣으면 예외가 제대로 캐치됩니다. 그러나 NSAssert이 대표 호출 (예 : didStartElement, didEndElement, foundCharacters)에서 실패한 경우 프로그램이 종료됩니다 (iPhone 시뮬레이터에서 아직 장치를 시도하지 않은 경우). 디버거 스택 추적은 어설 션이 예외로 발생했음을 나타내지 만 @try 블록이 [parser parse] 메시지 호출 인 최상위 레벨 코드로 되돌아 가지 않습니다. 대신 "잡히지 않는 예외로 인해 앱을 종료하는 중"이 표시됩니다.

이것이 알려진 문제인지 또는 내가 바보 같은 짓을하고 있는지 알려 주시기 바랍니다.

감사합니다 - 알렉스

일부 코드는 더 구체적으로 만들 수 있습니다. 이 코드를 메모리/릴리스/등으로 수정하려고 시도하지 않았습니다.

@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

프레임 워크 코드를 통해 예외를 전달하는 것은 항상 나쁜 생각입니다. 대리자 메서드에서 예외를 발생시키지 않아야합니다. –

+0

좋은 메모리 누출;) –

+0

Kevin - 고마워요, 그 패턴을 조심하겠습니다. tc - 예, 실제 코드는 좀 더주의해야하지만 적절한 메모리 관리 패턴을 배워야합니다. – Alex

답변

0

According to Bill Bumgarner iPhone 시뮬레이터에서 예외를 catch하면 올바르게 작동하지 않습니다. 어쨌든 실제로는 적절하지 않으므로 여기에서 예외 사용을 중단하는 것이 가장 좋습니다. 대신 -[NSXMLParser abortParsing]으로 전화해야합니다.

+0

감사합니다. 매우 유용합니다. 나는 단언문을 사용하는 것을 좋아하지만, 프로그래머 오류가 될만한 것을 사용한다고 믿는다. 누군가가 XML을 바꾸는 것은 실제 프로그래머 오류가 아니기 때문에 가능한 실제 오류로 취급하는 것이 가장 좋다. 여기에 프레임 워크 별 이유로 예외를 사용해서는 안됩니다. 감사! – Alex

0

흐름 제어에 예외를 사용하지 마십시오. 예외 안전 (Refcounted) Obj-C 코드를 작성하는 것은 특히 —의 통증이며, Foo * foo = [[Foo alloc] init]; [foo doStuff]; [foo release]; foo = nil;과 같이 일반적으로 사용되는 것들은 누출 될 것이며 [foo lock]; [foo doStuff]; [foo unlock];은 아마도 교착 상태가 될 것입니다. 당신은 autorelease 풀을 autorelease 할 수 없다는 점을 제외하고는 항상 autoreleasing을 즉시 수행함으로써 (코드를 리팩토링 할 때 항상 메모리 누수를 방지하기 위해) 자동으로 완화 할 수 있습니다. 후자는 당신이 @ try/@를 뿌리지 않는 한 피하기 힘듭니다. .

또한 강력하게은 objc_exception_throw()를 중단 점으로 지정하는 것이 좋습니다. 때로는 Xcode가 throw를 놓치고 스택이 도움이 안되게 풀린 후에 uncaught_exception_handler() (또는 호출 된 모든 것)에서 abort()가 호출 될 때 디버거로 빠져들기도합니다. 그리고 몇 가지 (특히 CoreAnimation)는 예외를 잡아 내고, 로그하고, 그렇지 않으면 무시합니다. 오랫동안보고 있지 않으면 디버깅하는 것이 어렵습니다.

제어 흐름에 예외가 사용 된 경우가 하나 있습니다 ("ControlThrow"라는 이름으로 생각합니다). 그 중단 점에 도달 할 때마다 나는 그것을 goto로 바꾸고 싶다.

+0

나는 흐름 제어를위한 예외를 사용하지 않는다는 것에 동의한다 - 내 의도가 아니었다. Kevin의 제안은 abortParsing을 사용하는 것이 더 쉽도록 도와 준다. 다른 제안을 해주셔서 감사합니다. – Alex