将Java代码移植到ObjC时,如何最好地表示已检查的exception?

我正在努力将Java代码库移植到Cocoa / Objective-C,以便在桌面Mac OS X上使用.Java代码有很多方法,例如:

double asNumber() throws FooException { ... } 

在Objective-C中表示这些的最佳方法是什么? 例外或错误输出参数?

 - (CGFloat)asNumber { ... // possibly [FooException raise:format:]; } 

要么

 - (CGFloat)asNumberError:(NSError **)outError { ... } 

我觉得out-errors通常是Objective-C的更好解决方案,但正如你所看到的……很多像上面那样的方法看起来很尴尬。 而且,还有很多这些。

当然要记住,由于这些是Java中的检查exception,我需要添加@try块或if (*outError) {...}检查调用这些方法的地方( 很多地方)。

我记得听说虽然在Objective-C中输入@try块曾经是昂贵的,但它在64位或SL或其他一些新的环境中是便宜的(不记得确切)。 我完全不关心向后兼容性,所以我绝对愿意只为新的热度而设计。

对于从字符串中解析数字这样的事情,你绝对应该避免例外 。 在Objective-C中,exception表示程序员错误,而不是用户输入错误,甚至是不可用的文件。 (部分原因是exception处理总是比更“常规”的error handling更加昂贵和复杂。无论在64位中输入@try块是“零成本”,只要实际发生exception,它仍然很慢当然,你可以随意使用exception,但它不是Cocoa方式,你会发现自己与其他Objective-C代码不一致。 使用您的代码的人会非常恼火,因为您会在导致错误的情况下抛出exception。

来自Apple自己的文档 :

“在许多环境中,使用exception是相当普遍的。例如,您可能会抛出exception来表示例程无法正常执行 – 例如当文件丢失或数据无法正确解析时。例外是资源密集型的在Objective-C中。您不应该使用exception来进行常规流控制,或者只是表示错误。相反,您应该使用方法或函数的返回值来指示发生了错误,并提供有关问题的信息。错误对象。“

看看内置的Cocoa类如何处理这样的错误。 例如, NSString具有-floatValue方法,如果失败则返回0。 针对您的特定情况的更好解决方案可能是NSScanner如何执行此操作,例如in -scanFloat: – 接受指向应存储结果的字段的指针,并根据解析是否成功返回YESNO

除了Obejctive-C约定和最佳实践之外,NSError比NSException更加健壮和灵活,并且允许调用者在需要时有效地忽略该问题。 我建议阅读error handling编程指南Cocoa 。 注意:如果您接受NSError**参数,我强烈建议您还设计允许客户端在不希望收到任何错误信息时传递NULL 。 我知道的每个Cocoa类都会出错,包括NSString。

虽然移植的代码最终可能看起来与Java代码完全不同,但要认识到它将由Objective-C代码使用,而不是Java等效的客户端。 绝对匹配语言的习语。 该端口不是Java代码的镜像,但结果会更加正确(对于Objective-C)。

在Cocoa中,exception实际上只应该用于“编程错误”; 理念是让应用程序捕获它们,让用户选择保存他们正在做的事情,然后退出。 首先,并非所有框架或代码路径都可以100%exception安全,因此这可能是唯一安全的操作过程。 对于可以预期和恢复的错误,您应该使用NSError,通常通过out-parameter。

你说“错误通常是ObjC的更好解决方案”是正确的。 您很少会在Cocoa中找到抛出exception的API(除非您不满足API的前提条件,但在这种情况下,默认情况下行为未定义)。

如果您希望此代码超越您并被其他Cocoa开发人员采用,我建议您使用错误。 我研究的是由不熟悉Cocoa的人构建的代码,他们自由地使用了exception,并且他们是一个很难解决的问题。

我是Objective-C使用的out错误方法的忠实粉丝。 您必须处理exception,但如果您愿意,可以选择忽略错误。 这一切都符合Objective-C的态度,即“程序员知道他们在做什么”。 它还使Objective-C成为一种非常干净的语言,因为你的代码不会被try-catch块混乱。

也就是说 – 您可能需要考虑:是否存在忽略exception的情况? 你抛出的例外真的很重要吗? 您是否发现自己编写简单的catch块来清理变量并继续? 我倾向于错误,因为我喜欢语法,而Objective-C只保留最关键错误的exception。

它看起来像这些检查的exception更干净地映射到错误。 仍可以使用例外情况,但应保留特殊情况。

exception可能是最好的方法,因为64位Obj-C ABI(运行时)使用零成本exception,因此您可以获得更清晰的代码而无需实际成本。 当然在32位中,旧的setjmp / longjmpexception仍然在使用,它们不与C ++交互,所以如果这是一个目标那么你就有问题了。