0) 避免 Cocoa 中的异常。它们通常是不可恢复的。您可能会在自己的错误报告中捕获它们,但假设您可以从中恢复通常是不安全的。
1)如果你需要抓住,就抓住它立即地. 不要写自己的抛出-- 相反,将其转换为类似NSError
并将其传递出去。NSError
可以包含显示或发送错误代码以及本地化消息所需的所有信息。
2) 您无法转换NSException
进入一个NSError
(直接)因为NSException
不具有所有属性NSError
有 - 这是一种不同的数据表示形式。其一,错误代码不可用。二是描述不本地化。您能做的最好的事情就是创建错误代码和域,然后使用您需要的属性NSException
并将其存储在NSError
。这可能类似于以下内容:
// 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);
...
}
如果您使用的 API 抛出异常,您需要捕获并从中恢复(例如,不是真正的异常情况),那么是的,您可以捕获并尝试继续。不幸的是,任何在 Cocoa 中编写异常并意图捕获它们的人可能都没有很好地理解这些问题,无法实现可靠的展开实现(例如,即使它产生泄漏,它也不是可靠的)。
3) 这确实不是显示警报的时间或地点。如果您安装顶级异常处理程序(通过NSSetUncaughtExceptionHandler
) - 您应该简单地记录一条消息——然后异常处理程序将中止。您的应用程序处于不稳定状态 - 继续比中止更糟糕。您可能想将这些自定义消息发送回家,最好在下次启动应用程序时这样做。
4) 在大多数情况下,您的应用程序处于不稳定状态,您不应该继续。但是,要真正回答这些极端情况:“是的,您可以在捕获时恢复并继续,但您应该仅在抛出 API 声明支持恢复时尝试恢复并继续。如果问题超出您的控制范围,并且问题并不例外(例如,找不到文件),并且供应商确实希望您继续,那么我必须假设他们希望您继续,即使它确实不是(100%安全)。”。不要尝试从顶级异常处理程序中恢复/继续(程序将在返回后中止)。如果您想要非常奇特并立即在 OSX 上呈现,那么另一个过程将是最好的。如果您通过纯 C++ 接口进行调用,则展开已明确定义,并且需要捕获 - 如果可以恢复,请继续。 C++ 中的异常是可恢复的并且定义良好 - 它们也被广泛使用(包括小于异常的条件)。
(IMO...)不应引入 ObjC 中的异常,并且应弃用从系统或第三方库抛出的任何方法。他们不能很好地放松,或者以一种明确的方式放松。同样,展开流程与正常的 Cocoa 程序流程相反。这意味着触摸任何 objc 对象的内存/关系(在抛出时发生突变并且位于抛出和捕获之间)与未定义的行为一样好。问题是 - 您不知道该内存是什么(在大多数情况下,并且在合理的维护时间内)。 C++ 异常定义良好,并且它们正确展开(例如调用析构函数) - 但尝试在 ObjC 上下文中继续会忽略未定义行为的任何后果。 IMO,它们应该只存在于 ObjC++ 中(因为 C++ 需要它们)。
在理想的世界中,您的 ObjC 程序和您使用的库不会(根本)使用异常。由于您使用会抛出异常的库(包括 Cocoa),因此请安装顶级异常处理程序仅当您需要有关错误的一些特殊信息时。 API 要求您可能会抛出异常由于您无法控制的情况,您预计会康复,然后编写一个 catch 但立即将该逻辑转换为正常的程序流(例如NSError
) - 你永远不需要编写自己的抛出。-[NSArray objectAtIndex:
和“对象不响应选择器”是程序员错误的例子 - 他们应该not会被抓住,但程序应该被纠正。