我是iPhone / Objective-C开发的新手,我使用NSXMLParser
成功解析XML但我无法获得正常工作的异常。我想使用异常来处理意外的XML。
我正在包装用于创建NSXMLParser
对象的代码,并将setDelegate和parse消息发送到@try
@catch
块内的对象,捕获@NSException
。< / p>
如果我将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)
According to Bill Bumgarner,在iPhone模拟器中捕获异常无法正常工作。你最好的办法是在这里停止使用例外,因为它无论如何都不合适。您应该改为呼叫-[NSXMLParser abortParsing]
。
答案 1 :(得分:0)
不要使用异常进行流量控制。编写异常安全(refcounted)的Obj-C代码有点痛苦 - 特别是像Foo * foo = [[Foo alloc] init]; [foo doStuff]; [foo release]; foo = nil;
这样常用的东西会泄漏,[foo lock]; [foo doStuff]; [foo unlock];
可能会死锁。您可以通过始终自动释放来缓解前者(我总是在重构代码时防止内存泄漏),除非您无法自动释放自动释放池。后者很难避免,除非你把@ try / @最后撒在。
此外,我强烈建议使用breakjinting objc_exception_throw()。有时Xcode似乎错过了抛出,并且在堆栈被无益地解开后从uncaught_exception_handler()(或其他任何调用的方法)调用abort()时,您将进入调试器。还有一些东西(特别是CoreAnimation)捕获,记录和忽略异常,这是一个很难调试,除非你看很长时间。
在应用程序中有一个案例,我使用控件流的异常(我想我给它起了名字“ControlThrow”);每当我点击那个断点时,我都很想用goto替换它。