我对iPhone的异常处理有一些疑问。以下是它们:
-
假设我有一个被一个接一个调用的方法链,也就是说,方法a调用方法B,方法B又调用方法C,方法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
-
我需要一些来自异常的错误代码(因为我的web服务需要参数错误代码和描述)。是否有可能将异常转换为错误,或者我是否需要硬编码此代码?
-
我在某个地方读过NSSetUncaughtExceptionHandler。我认为,如果我能设置这个handler(在app委托的appDidFinishLaunching方法中)在handler方法中,如果我向用户显示一些警报并调用web服务;那么我就不需要在我的每个方法中,在我的每个类中编写try - catch块。我说的对吗?
-
如果发生异常,并且我已经编写了try - catch块或NSSetUncaughtExceptionHandler,那么我的应用程序将继续运行或它将不响应任何用户事件。我相信它能应付这次崩溃。我想知道的是它是否会挂起
谁来给我讲讲这个例外的话题。
0)避免Cocoa中的异常。它们通常是不可恢复的。您可能会在自己的错误报告中捕获它们,但假设可以从中恢复通常是不安全的。
1)如果你需要抓住它,立即抓住它。不要编写自己的throw —相反,将其转换为类似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中编写异常的人,如果你想捕获它们,可能都没有很好地理解这个问题,无法实现一个可靠的unwind实现(例如,即使它产生泄漏,它也不是可靠的)。
3)那真的不是显示警告的时间和地点。如果您安装了一个顶级异常处理程序(通过NSSetUncaughtExceptionHandler
)——您应该简单地记录一条消息——那么异常处理程序将中止。你的应用处于不稳定状态——继续比中止更糟糕。你可能想把这些自定义消息发送回家,最好在下次启动你的应用程序时这样做。
(IMO…)ObjC中的异常不应该被引入,任何从系统或第三方库抛出的方法都应该被弃用。它们不能很好地展开,或者以一种明确的方式展开。同样,展开流与正常的Cocoa程序流相反。这意味着触摸任何对象的内存/关系,在抛出和捕获之间的抛出和未定义的行为的时间是在变化。问题是—您不知道内存是什么(在大多数情况下,并且在合理的维护时间内)。c++异常定义得很好,并且它们可以正确地展开(例如,调用析构函数)——但是试图在ObjC上下文中继续执行会忽略未定义行为的任何后果。在我看来,它们应该只存在于objc++中(因为c++需要它们)。
在理想情况下,您的ObjC程序和您使用的库不会使用异常(根本不会)。因为你使用的库会抛出(包括Cocoa),所以只有当你需要一些关于错误的特殊信息时,才安装一个顶级异常处理程序。如果API要求您可以预期由于超出您控制的情况而抛出异常,并且您希望恢复,那么编写一个catch,但立即将该逻辑转换为正常的程序流(例如NSError
) -您永远不需要编写自己的throw。-[NSArray objectAtIndex:
和"object does not response to selector"是程序员错误的例子——它们不应该被捕获,但是程序应该被纠正。