我刚刚完成 iPhone 应用程序编程课程。作为课程的一部分,我看到

  • Objective-C 使用以下方法提供异常处理 @try 指示
  • 系统库不使用异常处理,更喜欢 return nil

我问我是否应该对我编写的新代码使用异常处理(例如如果我同时编写前端和逻辑代码,那么它们之间的通信就在我手中)但我被告知不,不应该在新代码中使用异常。(但他没有详细说明,然后课程继续进行,我想也许稍后原因就会清楚..)

当然例外优于 return nil?您可以捕获特定类型,您不会试图通过忽略通常成功的函数的返回类型来忽略它们,您有可以记录的文本消息,它们允许您的代码专注于正常情况,从而更具可读性。 为什么要使用异常.

所以你怎么看?我的培训师不使用 Objective-C 异常是正确的吗?如果是这样,为什么?

有帮助吗?

解决方案

在不自动管理资源的情况下,抛出例外是不安全的。可可框架(和邻居框架)是这种情况,因为它们使用手动参考计数。

如果您抛出例外,任何 release 通过放开堆栈来打电话给您跳过,将导致泄漏。仅当您确定自己不会恢复时,这才能限制您的工作,因为当过程退出时,所有资源都返回到操作系统。

很遗憾, NSRunLoopS倾向于捕获所有传播它们的例外,因此,如果您在活动期间投掷,您将恢复下一个活动。显然,这很糟糕。因此,最好不要扔。

如果您使用垃圾收集的Objective-C,则此问题会减少,因为Objective-C对象表示的任何资源都将被正确发布。但是,C资源(例如文件描述符或 malloc- 未包裹在Objective-C对象中的分配内存)仍将泄漏。

因此,总的来说,不要扔。

正如您提到的那样,可可API对此有多种解决方法。返回 nilNSError** 图案是其中两个。

弧的澄清

ARC用户可以选择启用或禁用完全异常安全。当启用例外安全性时,ARC将生成代码以释放其范围时发布强引用,从而安全使用例外 在您的代码中. 。 ARC不会修补外部库以启用它们的异常支持,因此即使在程序中启用了例外支持,也应该小心地扔掉的位置(尤其是在捕获的地方)。

可以启用ARC异常支持 -fobjc-arc-exceptions 或禁用 -fno-objc-arc-exceptions. 。默认情况下,它在Objective-C中被禁用,但在Objective-C ++中启用。

默认情况下,Objective-C中的完全例外安全性是禁用的,因为Clang的作者认为Objective-C程序无论如何都不会从异常中恢复,并且由于该清理的代码尺寸成本较大,而且绩效较小。另一方面,在Objective-C ++中,C ++已经引入了许多清理代码,人们更有可能需要异常安全。

这全是从 LLVM网站上的ARC规范.

其他提示

在 Cocoa 和 iOS 编程中,异常用于指示不可恢复的程序员错误。当框架抛出异常时,表明框架检测到不可恢复且内部状态现在未定义的错误状态。

此外,通过框架代码抛出的异常会使框架处于未定义状态。IE。你不能这样做:

void a() {
    @throw [MyException exceptionWithName: @"OhNoes!"  ....];
}

@try {
    ... call into framework code that calls a() above ...
} @catch (MyException e) {
    ... handle e ...
}

底线:

Cocoa 中不得使用异常进行流程控制、用户输入验证、数据有效性检测或以其他方式指示可恢复的错误。为此,您使用 NSError** 模式为 记录在这里 (感谢阿比泽姆)。

(请注意,有少数 API 确实违反了这一点——其中使用异常来指示可恢复状态。已针对这些问题提交了错误,以弃用并最终消除这些不一致之处。)


最后 找到了文档 我在寻找:

重要的: 您应该保留使用异常来编程或意外的运行时错误,例如越野外收集访问,试图突变不变的对象,发送无效的消息并将连接失去到窗口服务器。通常,当创建应用程序而不是在运行时,您会处理这些错误,而例外。

如果您使用使用异常来处理错误条件的现有代码(例如第三方库),则可以在可可应用程序中使用代码。但是,您应该确保任何预期的运行时例外都不会脱离这​​些子系统,而最终进入呼叫者的代码。例如,解析库可能会在内部使用异常来指示问题,并可以从解析状态中快速退出,该状态可能具有深刻的递归;但是,您应该小心地在图书馆的最高级别捕获此类例外,并将其转换为适当的返回代码或状态。

我认为,如果我错了,其他人会纠正我,应该使用例外来捕获程序员错误,而 NSError 类型错误处理应用于程序运行时发生的特殊情况。

至于返回 nil, ,这不是全部 - 可能有问题的函数不仅要返回 nil, ,他们还可以(并且应该)使用作为参数传递的nserror对象提供进一步的信息。

也可以看看

就个人而言,我认为没有理由不使用异常 在您自己的代码中. 。异常模式比处理错误更干净

  • 始终具有回报值,
  • 确保可能的返回值之一真正意味着“错误”
  • 传递额外参数,这是对 NSError*
  • 使用清理代码洒上代码,以返回每个错误或让明确的GOTO跳到常见的错误清理部分。

但是,您需要记住,不能保证其他人的代码能够正确处理异常(如果是纯粹的C,实际上是 不能 正确处理异常)。因此,您绝不能允许例外来传播代码的边界。例如,如果您在代表方法的肠子中深处抛出一个例外, 您必须在返回代表消息的发件人之前处理该例外.

使用的错误处理类型取决于 什么 您正在尝试完成。苹果的几乎所有方法都会填充 NSError 错误时可以访问的对象。

这种类型的错误处理可以与代码部分中的一个try-catch块一起使用:

-(NSDictionary *)getDictionaryWithID:(NSInteger)dictionaryID error:(NSError **)error
{
    @try
    {
         //attempt to retrieve the dictionary
    }
    @catch (NSException *e)
    {
        //something went wrong
        //populate the NSError object so it can be accessed
    }
}

简而言之,该方法的目的确定了您应该使用的错误处理类型。但是,在上面的示例中,您可以两者都使用。

Try-Catch块的常用用途:

@try
{
    [dictionary setObject:aNullObject forKey:@"Key"];
}
@catch (NSException *e)
{
    //one of the objects/keys was NULL
    //this could indicate that there was a problem with the data source
}

希望这可以帮助。

我认为你的教练是正确的。您可以提出各种支持或反对异常的论据,但最重要的是,如果您希望经验丰富的 Cocoa 开发人员能够正确地“闻到”您的代码,那么您将使用 Apple 在其代码中使用的相同设计模式来实现您的应用程序,并且在他们的框架中。这意味着 nilNSErrors 而不是异常。

因此,不使用异常的优点主要在于一致性和熟悉性。

另一件需要考虑的事情是 nil 在目标中,通常C通常是“安全的”。也就是说,您可以将任何消息发送给 nil 并且您的应用程序不会崩溃。

(我还应该指出,苹果 在某些地方使用异常,通常是在错误使用 API 的地方。)

如果您喜欢异常,则可以使用它们。如果您这样做,我建议您很少使用它们,因为它很难维护(其他出口点通常必须在运行时锻炼才能证明程序的正确性)。

没有针对客户的例外处理期望的规范;他们必须根据文档维护程序(乏味,容易发生的错误,直到抛出例外,可能才能维护)。

如果我要使用它们,我将仅在非常罕见的情况下使用它们,并使用错误代码或在可能的情况下返回零。另外,我将它们在库中内部使用,而不会使客户端接口(或副作用)中的异常。我不在OBJC或C ++中使用它们(好吧,我会抓住它们,但我不会扔它们)。

正如您通常期望的那样,您应该避免使用它们来控制程序流(常见的滥用)。

当您必须逃脱某个崩溃时,最好使用它们。如果您现在要继续编写代码,我建议您只编写界面以处理错误作为程序流的一部分,并在可能的情况下避免编写异常。

对原始帖子的纠正:可可液喜欢零零,在某些情况下,他们会为您提供例外(捕捉)。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top