整个应用程序中的异常处理 [英] Exception handling in entire application

查看:146
本文介绍了整个应用程序中的异常处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对iPhone中的异常处理有一些疑问。这里是:


  1. 假设我有一连串的方法被一个接一个地调用,也就是方法A调用方法B,依次调用方法C,调用方法D.哪个是最好的地方放置我的try-catch块(是方法A或B或C或D或所有它们)。此外,我需要向用户显示一个异常发生的警报,然后,我想将此异常记录到我的服务器。所以,如果我在所有这些方法中写我的try-catch块,如果在方法D中发生异常,那么我觉得警报将显示4次,Web服务记录也将被调用4次(直到控制到达方法A的块)。所以,我应该用@throw在方法B,C和D的catch块中,将我的逻辑写入方法A(顶级方法)的catch块中,或者应该避免在方法B,C和D中写入try-catch。


  2. 我需要某种异常的错误代码(因为我的Web服务需要参数错误代码和描述)。有可能将异常转换为错误,还是需要对代码进行硬编码?


  3. 我已经读过NSSetUncaughtExceptionHandler的某个地方。我想,如果我可以设置这个处理程序(在appDidFinishLaunching方法中的app delegate)和处理程序方法,如果我向用户显示一些警报并调用Web服务;那么我不需要在每个我的类中的每个方法中写try - catch块。我是对的?


  4. 如果发生异常,我已经写过一个try-catch块或NSSetUncaughtExceptionHandler,那么我的应用程序是否继续运行,不响应任何用户事件。 (我确定会处理崩溃,我想知道是否会挂起)


有人请在这个例外主题中启发我。

解决方案

0)在Cocoa中避免异常。它们通常是不可恢复的。你可能会抓住他们自己的错误报告,但假设你可以从他们那里恢复一般是不安全的。



1)如果你需要抓住它,抓住它立即不要写自己的投票 - 而是将其转换为类似于 NSError 并将其转发的内容。 NSError 可以包含显示或发送错误代码以及本地化消息所需的所有信息。



2)您不能将 NSException 转换为 NSError (直接),因为 NSException 没有所有属性一个 NSError has - 它是一个不同的数据表示。一个错误代码不可用。二,描述没有本地化。最好的方法是创建错误代码和域,然后使用 NSException 中所需的属性,并将其存储在 NSError 。这可能看起来像以下内容:

  //错误检查省略
extern NSString * const MONExceptionHandlerDomain;
extern const int MONNSExceptionEnoveredErrorCode;

NSError * NewNSErrorFromException(NSException * exc){
NSMutableDictionary * info = [NSMutableDictionary dictionary];
[info setValue:exc.name forKey:@MONExceptionName];
[info setValue:exc.reason forKey:@MONExceptionReason];
[info setValue:exc.callStackReturnAddresses forKey:@MONExceptionCallStackReturnAddresses];
[info setValue:exc.callStackSymbols forKey:@MONExceptionCallStackSymbols];
[info setValue:exc.userInfo forKey:@MONExceptionUserInfo];

return [[NSError alloc] initWithDomain:MONExceptionHandlerDomain代码:MONNSExceptionEnceedErrorCode userInfo:info];
}

@catch(NSException * exc){
NSError * err = NewNSErrorFromException(exc);
...
}

如果您使用的API抛出异常,则为预计会捕获并恢复(例如,不是真正的例外情况),那么是的,你可以抓住并试图继续。不幸的是,任何在Cocoa中写入异常的人,意图是抓住他们可能无法理解实施一个坚实的退出实现的问题(例如,即使它产生泄漏,也不是很稳固)。



3)这真的不是显示警报的时间或地点。如果你安装一个顶级异常处理程序(通过 NSSetUncaughtExceptionHandler ) - 你应该简单地记录消息 - 然后异常处理程序将中止。您的应用程序处于不稳定的状态 - 持续不止于中止。您可能希望将这些自定义消息发送回家,最好在下次启动应用程序时执行此操作。



4)在大多数情况下,您的应用程序一个不稳定的状态,你不应该继续。但是,为了真正回答这些角色的情况:是的,你可以恢复并继续,当你抓住,但你应该只尝试恢复和继续,当抛出的API声明恢复被支持如果这个问题超出了你的控制,而这个问题并不例外(例如,文件未找到),供应商真的希望你能继续下去,那么我必须假设他们希望你继续下去,尽管它真的不是(100%安全的)。不要尝试从顶级异常处理程序中恢复/继续(程序将在返回后中止)。如果您想要在OSX上非常喜欢并立即呈现,另一个过程将是最好的。如果您通过纯C ++接口调用,那么展开定义很好,需要捕获就是必要的 - 如果可以恢复,则继续执行。 C ++中的异常可以被恢复和定义良好 - 它们也被广泛使用(包括少于特殊条件)。



(IMO ...)ObjC中的异常不应该已被引入,任何从系统或第三方库抛出的方法都应被弃用。他们不能很好地放松,或者以一个明确的方式。同样,解决流程反对正常的可可程序流程。这意味着触摸任何objc对象的内存/关系,在抛出时处于突变中,并且位于throw和catch之间的记忆/关系与未定义的行为一样好。问题是 - 你不知道记忆是什么(在大多数情况下,在合理的维护时间内)。 C ++异常被很好地定义,并且它们正确地展开(例如析构函数被调用) - 但是尝试在ObjC上下文中继续忽略未定义行为的任​​何后果。 IMO,它们应该仅存在于ObjC ++(因为C ++需要它们)。



在理想的世界中,您的ObjC程序和您使用的库不会使用异常)。由于您使用抛出(包括Cocoa)的库,只有在需要有关错误的特殊信息时才安装顶级异常处理程序。由于API要求您可能期望由于您无法控制的情况引发异常,因此您希望恢复,然后写入捕获,但立即将该逻辑转换为正常的程序流程(例如 NSError ) - 你永远不需要自己写。 - [NSArray objectAtIndex:和对象不响应选择器是程序员错误的示例 - 他们应该被捕获,但程序应该要更正。


I have a few doubts regarding exception handling in iPhone. Here are they:

  1. Suppose I have a chain of methods which are being called one after the other, that is, method A calls method B, which in turn calls method C, which calls method D. Which is the best place to put my try-catch block (is it method A or B or C or D or all of them). Also, I need to display an alert to user that an exception has occured and then, I want to log this exception to my server. So, if I am writing my try - catch block in all of this methods and if an exception occurs in method D; then I think the alert will be displayed 4 times and the web service for logging will also be called 4 times (till control reaches to catch block of method A). So, should I just use @throw; in catch block of method B, C and D and write my logic in catch block of method A (top level method) or should I avoid writing try - catch at all in methods B,C and D.

  2. I need some sort of error code from the exception (because my web service needs parameters error-code and description). Is it possible to convert an exception to error or will I need to hard-code this code?

  3. I had read somewhere about NSSetUncaughtExceptionHandler. And I think, if I can set this handler (in appDidFinishLaunching method of app delegate) and in the handler method, if I show to user some alert and call the web service; then I need not write try - catch block in each of my methods, in each of my classes. Am I right??

  4. If an exception has occured and I have written either a try - catch block or NSSetUncaughtExceptionHandler, then will my app continue running or it will not respond to any of the user events. (I am sure it will handle the crash. What I want to know is whether it will hang)

Someone please enlighten me on this EXCEPTION TOPIC.

解决方案

0) Avoid exceptions in Cocoa. They are generally non-recoverable. You might catch them for your own error reporting, but it's generally unsafe to assume you can recover from them.

1) If you need to catch, catch it immediately. Don't write your own throws -- instead, convert it to something like an NSError and pass that around. NSError can contain all the information you need to display or send an error code as well as a localized message.

2) You cannot convert an NSException into an NSError (directly) because an NSException does not have all the properties an NSError has - it is a different data representation. For one, an error code is not available. Two, the description is not localized. The best you can do is to create an error code and domain, then use the properties you need from the NSException and store that in an NSError. This could look something like the following:

// error checking omitted
extern NSString* const MONExceptionHandlerDomain;
extern const int MONNSExceptionEncounteredErrorCode;

NSError * NewNSErrorFromException(NSException * exc) {
    NSMutableDictionary * info = [NSMutableDictionary dictionary];
    [info setValue:exc.name forKey:@"MONExceptionName"];
    [info setValue:exc.reason forKey:@"MONExceptionReason"];
    [info setValue:exc.callStackReturnAddresses forKey:@"MONExceptionCallStackReturnAddresses"];
    [info setValue:exc.callStackSymbols forKey:@"MONExceptionCallStackSymbols"];
    [info setValue:exc.userInfo forKey:@"MONExceptionUserInfo"];

    return [[NSError alloc] initWithDomain:MONExceptionHandlerDomain code:MONNSExceptionEncounteredErrorCode userInfo:info];
}

@catch (NSException * exc) {
    NSError * err = NewNSErrorFromException(exc);
    ...
}

If the APIs you use throw exceptions you are expected to catch and recover from (e.g. not truly exceptional cases), then yes, you could catch and attempt to continue. Unfortunately, anybody that writes exceptions in Cocoa with the intent that you will catch them probably does not understand the issues well enough to implement a solid unwind implementation (e.g. even if it produces leaks, it's not solid).

3) That's really not the time or place to display an alert. If you install a top level exception handler (via NSSetUncaughtExceptionHandler) - You should simply log a message -- then the exception handler will abort. Your app is in an unstable state -- continuing is worse than aborting. You may want to send these custom messages home, it's best to do so at the next launch of your app.

4) In the majority of cases, your app is in an unstable state and you should not continue. But, to actually answer it for those corner cases: "Yes, you can recover and continue when you catch, but you should only attempt to recover and continue when the throwing API states that recovery is supported. If the problem is beyond your control, and the problem is not exceptional (e.g. file not found), and the vendor really expects you to continue, then I would have to assume that they expect you to continue, even though it really isn't (100% safe).". Do not attempt to recover/continue from within your top level exception handler (the program will abort after it returns). If you want to be very fancy and present that immediately on OSX, another process would be best. If you are calling through a pure C++ interface, then the unwinding is well defined, and the need to catch is necessary - do continue if it is recoverable. Exceptions in C++ can be recoverable and well defined - they are also used quite extensively (including less than exceptional conditions).

(IMO...) Exceptions in ObjC should not have been introduced, and any method that throws from system or third party libraries should be deprecated. They don't unwind well, or in a well defined manner. As well, unwinding flows against normal Cocoa program flow. That means that touching any objc object's memory/relations that was in mutation at the time of the throw and which lies between the throw and the catch is as good as undefined behaviour. Problem is - you have no idea what that memory is (in most cases, and within reasonable maintenance time). C++ exceptions are well defined, and they unwind correctly (e.g. destructors are called) - but trying to continue in an ObjC context is ignoring any consequences of undefined behavior. IMO, they should only exist for ObjC++ (because C++ requires them).

In an ideal world, your ObjC programs and the libraries you use would not use exceptions (at all). Since you use libraries that do throw (including Cocoa), install a top level exception handler only if you need some special information about the error. Where the API mandates that you could expect an exception thrown due to circumstances beyond your control and you are expected to recover, then write a catch but immediately convert that logic to normal program flow (e.g. NSError) - you never need to write your own throw. -[NSArray objectAtIndex: and "object does not respond to selector" are examples of programmer errors - they should not be caught, but the program should be corrected.

这篇关于整个应用程序中的异常处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆