在iPhone应用中使用NSexception
-
29-09-2019 - |
题
我的一个朋友要求我不要在iPhone应用中使用NSexception。他给出的原因是“表演瓶颈”。但是我不相信这一点。
有人可以确认我应该克制iPhone应用中使用NSexception吗?如果您有使用NSexception的最佳实践,请也提供。
更新:
这 关联 请求我们在应用程序级别使用异常处理。有人做过吗?请给出它的优势以及它可能创建的任何其他性能障碍。
解决方案
简而言之:
请勿使用异常来指示任何内容,但无法恢复错误
仅使用 @try/ @catch来处理不可撤销的错误是合适的。使用@throw/@try/@catch绝不合适,例如在iOS或Mac OS X上进行操作。致电Abort());坠机通常留下更多的证据。
例如,除非您的目标是捕获它们并以某种方式报告错误,否则使用遇到的异常是不合适的处于不一致的状态,可能会丢失数据。
通过系统框架代码抛出的任何例外的行为均未定义。
您能否解释“通过系统框架代码抛出的任何例外的行为是不确定的”。详细地?
当然。
系统框架使用设计,其中任何例外都被认为是致命的,不可恢复的错误;程序员错误,出于所有意图和目的。该规则的例外数量非常有限。
因此,在其实施中,如果抛弃了通过系统框架代码的异常,则系统框架将无法确保一切都必须正确清理。从定义上讲,正弦的例外是为什么要支付清理费用?
考虑此通话堆栈:
your-code-1()
system-code()
your-code-2()
即代码在系统代码中调用代码,该代码将其调用到更多的代码中(尽管调用堆栈显然更深,但非常常见的模式)。
如果 your-code-2
引发例外,例外已经过去了 system-code
意味着行为不确定; system-code
可能会或可能不会将您的应用程序留在未定义的,可能崩溃或数据遗憾的状态中。
或者,更强烈:您不能在 your-code-2
期望您可以抓住并处理它 your-code-1
.
其他提示
我已经使用了例外处理来进行密集 音频应用程序 没有任何问题。经过大量阅读和一些基准测试和拆卸分析之后,我得出了一个有争议的结论,没有真正的理由不使用它们(聪明地)和很多理由不使用(nserror指针,无穷无尽的条件... youck!)。人们在论坛上所说的大多数只是重复Apple文档。
我详细介绍了 这篇博客文章 但是我将在这里概述我的发现:
误解1:@try/@catch/@终于太贵了(就CPU而言)
在我的iPhone 4上,投掷和捕获100万个例外大约需要8.5秒。这相当于每个小微秒约8.5微秒。您的实时CoreAudio线程昂贵?也许有点(但是您永远不会抛出例外吗?
误解2:@Try Blocks在32位iOS上的费用
苹果文档说“零成本@try块 64位“并指出32位会产生成本。一些基准测试和拆卸分析似乎表明32位iOS(ARM处理器)上也有零成本@Try块。苹果的意思是说32bit 英特尔?
误解3:重要的是,通过可可框架抛出的例外是不确定的
是的,它们是“未定义的”,但是您在Apple框架上投掷什么? 当然 苹果不为您处理它们。 实现可回收错误的异常处理的全部要点是在本地处理它们 - 并非每个单行线“本地”。
这里的一个边缘情况是使用类似的方法 NSObject:performSelectorOnMainThread:waitUntilDone:
. 。如果以后的参数是肯定的,那么这就像同步函数,在这种情况下,您可能会因为期望异常而闻到呼叫范围而被原谅。例如:
/////////////////////////////////////////////////////////////////////////
#pragma mark - l5CCThread
/////////////////////////////////////////////////////////////////////////
@interface l5CCThread : NSThread @end
@implementation l5CCThread
- (void)main
{
@try {
[self performSelectorOnMainThread:@selector(_throwsAnException) withObject:nil waitUntilDone:YES];
} @catch (NSException *e) {
NSLog(@"Exception caught!");
}
}
- (void)_throwsAnException { @throw [NSException exceptionWithName:@"Exception" reason:@"" userInfo:nil]; }
@end
/////////////////////////////////////////////////////////////////////////
#pragma mark - l5CCAppDelegate
/////////////////////////////////////////////////////////////////////////
@implementation l5CCAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
l5CCThread *thd = [[l5CCThread alloc] init];
[thd start];
return YES;
}
// ...
在这种情况下,例外将通过“通过可可框架”(主线程的运行循环)错过了您的捕获和崩溃。您可以使用GCD轻松解决此问题 dispatch_synch
并放入它的块参数,方法调用以及任何异常处理。
为什么要在nserror上使用nsexception
任何曾经在基于C的旧框架之一(例如Core Audio)中完成工作的任何人都知道它正在检查,处理和报告错误。主要好处 @try/ @catch和nSexceptions提供的是使您的代码更清洁且易于维护。
假设您有5行代码,可以在文件上使用。每个都可能会丢弃3个不同的错误(例如,磁盘空间,读取错误等)。与其将每行的条件包装在任何条件下检查无返回值,然后将NSERROR指针调查外包给另一种OBJC方法(或更糟糕的是,使用 #define
宏!),您将所有5行包裹在 一个 @Try并在那里处理每个错误。考虑一下您将保存的行!
通过创建NSexception子类,您还可以轻松地集中错误消息,并避免将代码乱扔。您还可以轻松地将应用程序的“非致命”例外区分开,并将其与致命程序员错误(如NSASSERT)区分开。您还可以避免需要“名称”常数(子类的名称为“名称”)。
所有这些示例以及有关基准和拆卸的更多详细信息是 在此博客文章中...
异常加尝试/捕获/最后是几乎所有其他主要语言(C ++,Java,PHP,Ruby,Python)使用的范式。也许是时候放下偏执狂并拥抱它……至少在iOS中。
通常问自己是要发出错误的信号,还是实际上有特殊情况?如果前者,那么无论出现任何表现问题,这都是一个非常糟糕的主意。如果后者,这绝对是正确的事情。