一尘不染

Swift语言中的错误处理

swift

我对Swift的了解还不够多,但是我注意到的一件事是没有例外。那么如何在Swift中进行错误处理呢?有没有人发现任何与错误处理相关的信息?


阅读 261

收藏
2020-07-07

共1个答案

一尘不染

斯威夫特2&3

Swift 2中的情况有所变化,因为有了新的错误处理机制,该机制与异常有些相似,但在细节上有所不同。

1.指示错误可能性

如果函数/方法想要表明它可能抛出错误,则应包含这样的throws关键字

func summonDefaultDragon() throws -> Dragon

注意:函数没有实际抛出的错误类型的规范。 该声明只是声明该函数可以抛出实现ErrorType的任何类型的实例,或者根本不抛出该实例。

2.调用可能引发错误的功能

为了调用函数,您需要使用try关键字,像这样

try summonDefaultDragon()

该行通常应该像这样出现在do-catch块中

do {
    let dragon = try summonDefaultDragon() 
} catch DragonError.dragonIsMissing {
    // Some specific-case error-handling
} catch DragonError.notEnoughMana(let manaRequired) {
    // Other specific-case error-handlng
} catch {
    // Catch all error-handling
}

注意:catch子句使用Swift模式匹配的所有强大功能,因此您在这里非常灵活。

如果您正在从本身用throws关键字标记的函数中调用throwing函数,则可以决定传播错误:

func fulfill(quest: Quest) throws {
    let dragon = try summonDefaultDragon()
    quest.ride(dragon)
}

另外,您可以使用try?以下命令调用throwing函数:

let dragonOrNil = try? summonDefaultDragon()

这样,如果发生任何错误,您将获得返回值或nil。使用这种方式,您不会得到错误对象。

这意味着您还可以结合以下try?有用的语句:

if let dragon = try? summonDefaultDragon()

要么

guard let dragon = try? summonDefaultDragon() else { ... }

最后,您可以确定知道实际上不会发生错误(例如,因为您已经检查过先决条件),并使用try!关键字:

let dragon = try! summonDefaultDragon()

如果该函数实际引发错误,则您的应用程序中将出现运行时错误,并且该应用程序将终止。

3.引发错误

为了抛出错误,您可以使用throw这样的关键字

throw DragonError.dragonIsMissing

您可以抛出任何符合ErrorType协议的内容。对于初学者来说,NSError遵循此协议,但您可能希望使用基于枚举的枚举,ErrorType该枚举使您可以将多个相关的错误归为一组,并可能附加其他数据,例如:

enum DragonError: ErrorType {
    case dragonIsMissing
    case notEnoughMana(requiredMana: Int)
    ...
}

新的Swift 2和3错误机制与Java / C#/ C ++样式异常之间的主要区别如下:

  • 语法是有点不同:do-catch+ try+ deferVS传统的try-catch-finally语法。
  • 异常处理通常会导致异常路径中的执行时间比成功路径中的执行时间长得多。Swift 2.0错误并非如此,成功路径和错误路径的成本大致相同。
  • 必须声明所有错误抛出代码,而异常可能已从任何地方抛出。所有错误都是Java术语中的“检查的异常”。但是,与Java相比,您没有指定可能引发的错误。
  • Swift异常与ObjC异常不兼容。您的do-catch块将不会捕获任何NSException,反之亦然,因为您必须使用ObjC。
  • Swift异常与NSError返回false(对于Bool返回函数)或nil(对于AnyObject返回函数)并传递NSErrorPointer错误详细信息的Cocoa 方法约定兼容。

作为减轻错误处理的额外语法糖,还有两个概念

  • 延迟操作(使用defer关键字),使您可以实现与Java / C#/ etc中的finally块相同的效果
  • 保护语句(使用guard关键字),使您编写的if / else代码比普通的错误检查/信号代码少。

斯威夫特1

运行时错误:

正如Leandros建议处理运行时错误(如网络连接问题,解析数据,打开文件等)一样,您应该NSError像在ObjC中一样使用,因为Foundation,AppKit,UIKit等以这种方式报告错误。因此,与其说是语言,不如说是框架。

另一个经常使用的模式是分隔符成功/失败块,例如AFNetworking中:

var sessionManager = AFHTTPSessionManager(baseURL: NSURL(string: "yavin4.yavin.planets"))
sessionManager.HEAD("/api/destoryDeathStar", parameters: xwingSquad,
    success: { (NSURLSessionDataTask) -> Void in
        println("Success")
    },
    failure:{ (NSURLSessionDataTask, NSError) -> Void in
        println("Failure")
    })

故障块仍然是频繁接收的NSError实例,描述了错误。

程序员错误:

对于程序员错误(例如对数组元素的越界访问,传递给函数调用的无效参数等),您在ObjC中使用了异常。雨燕语言似乎并未有任何异常的语言支持(如throwcatch等关键字)。但是,正如文档所示,它与ObjC在同一运行时上运行,因此您仍然可以这样抛出NSExceptions

NSException(name: "SomeName", reason: "SomeReason", userInfo: nil).raise()

尽管您可能选择在ObjC代码中捕获异常,但是您无法在纯Swift中捕获它们。

问题是您是否应该为程序员错误抛出异常,还是应该像苹果在语言指南中建议的那样使用断言。

2020-07-07