Swift 语言中的错误处理 [英] Error-Handling in Swift-Language
问题描述
我对 Swift 的了解不多,但我注意到的一件事是没有例外.那么他们如何在 Swift 中进行错误处理呢?有没有人发现任何与错误处理相关的东西?
I haven't read too much into Swift but one thing I noticed is that there are no exceptions. So how do they do error handling in Swift? Has anyone found anything related to error-handling?
推荐答案
Swift 2 & 3
在 Swift 2 中,事情发生了一些变化,因为有一个新的错误处理机制,有点类似于异常,但在细节上有所不同.
Swift 2 & 3
Things have changed a bit in Swift 2, as there is a new error-handling mechanism, that is somewhat more similar to exceptions but different in detail.
如果函数/方法想表明它可能会抛出错误,它应该包含像这样的throws
关键字
If function/method wants to indicate that it may throw an error, it should contain throws
keyword like this
func summonDefaultDragon() throws -> Dragon
注意:没有指定函数实际可以抛出的错误类型.此声明只是声明该函数可以抛出实现 ErrorType 的任何类型的实例或根本不抛出.
为了调用函数,你需要使用 try 关键字,就像这样
In order to invoke function you need to use try keyword, like this
try summonDefaultDragon()
这一行通常应该像这样出现 do-catch 块
this line should normally be present do-catch block like this
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
关键字标记的函数调用抛出函数,您可能决定传播错误:
You may decided to propagate the error, if your are calling a throwing function from a function that is itself marked with throws
keyword:
func fulfill(quest: Quest) throws {
let dragon = try summonDefaultDragon()
quest.ride(dragon)
}
或者,您可以使用 try?
调用 throwing 函数:
Alternatively, you can call throwing function using try?
:
let dragonOrNil = try? summonDefaultDragon()
如果发生任何错误,您可以通过这种方式获得返回值或 nil.使用这种方式你不会得到错误对象.
This way you either get the return value or nil, if any error occurred. Using this way you do not get the error object.
这意味着您还可以将 try?
与有用的语句结合起来,例如:
Which means that you can also combine try?
with useful statements like:
if let dragon = try? summonDefaultDragon()
或
guard let dragon = try? summonDefaultDragon() else { ... }
最后,您可以决定您知道错误实际上不会发生(例如,因为您已经检查了先决条件)并使用 try!
关键字:
Finally, you can decide that you know that error will not actually occur (e.g. because you have already checked are prerequisites) and use try!
keyword:
let dragon = try! summonDefaultDragon()
如果该函数确实抛出了错误,那么您的应用程序将出现运行时错误,应用程序将终止.
If the function actually throws an error, then you'll get a runtime error in your application and the application will terminate.
为了抛出一个错误,你可以像这样使用 throw 关键字
In order to throw an error you use throw keyword like this
throw DragonError.dragonIsMissing
你可以抛出任何符合 ErrorType
协议的东西.对于初学者来说,NSError
符合此协议,但您可能希望使用基于枚举的 ErrorType
,它使您能够对多个相关错误进行分组,可能带有附加数据,例如这个
You can throw anything that conforms to ErrorType
protocol. For starters NSError
conforms to this protocol but you probably would like to go with enum-based ErrorType
which enables you to group multiple related errors, potentially with additional pieces of data, like this
enum DragonError: ErrorType {
case dragonIsMissing
case notEnoughMana(requiredMana: Int)
...
}
<小时>
新 Swift 2 和 Swift 之间的主要区别3 错误机制和Java/C#/C++风格的异常如下:
Main differences between new Swift 2 & 3 error mechanism and Java/C#/C++ style exceptions are follows:
- 语法有点不同:
do-catch
+try
+defer
vs 传统的try-catch-finally
语法. - 异常处理在异常路径中的执行时间通常比在成功路径中长得多.Swift 2.0 错误并非如此,成功路径和错误路径的成本大致相同.
- 必须声明所有错误抛出代码,而异常可能已从任何地方抛出.所有错误都是 Java 术语中的检查异常".但是,与 Java 不同的是,您没有指定可能抛出的错误.
- Swift 异常与 ObjC 异常不兼容.您的
do-catch
块不会捕获任何 NSException,反之亦然,为此您必须使用 ObjC. - Swift 异常与 Cocoa
NSError
返回false
(对于Bool
返回函数)或nil
方法约定兼容code>(用于AnyObject
返回函数)并传递带有错误详细信息的NSErrorPointer
.
- Syntax is a bit different:
do-catch
+try
+defer
vs traditionaltry-catch-finally
syntax. - Exception handling usually incurs much higher execution time in exception path than in success path. This is not the case with Swift 2.0 errors, where success path and error path cost roughly the same.
- All error throwing code must be declared, while exceptions might have been thrown from anywhere. All errors are "checked exceptions" in Java nomenclature. However, in contrast to Java, you do not specify potentially thrown errors.
- Swift exceptions are not compatible with ObjC exceptions. Your
do-catch
block will not catch any NSException, and vice versa, for that you must use ObjC. - Swift exceptions are compatible with Cocoa
NSError
method conventions of returning eitherfalse
(forBool
returning functions) ornil
(forAnyObject
returning functions) and passingNSErrorPointer
with error details.
作为一种额外的语法糖来简化错误处理,还有两个概念
As an extra syntatic-sugar to ease error handling, there are two more concepts
- 延迟操作(使用
defer
关键字),让您实现与 Java/C#/etc 中的 finally 块相同的效果 - guard 语句(使用
guard
关键字)让您编写的 if/else 代码比普通错误检查/信号代码少一点.
- deferred actions (using
defer
keyword) which let you achieve the same effect as finally blocks in Java/C#/etc - guard statement (using
guard
keyword) which let you write little less if/else code than in normal error checking/signaling code.
运行时错误:
正如 Leandros 建议的处理运行时错误(如网络连接问题、解析数据、打开文件等),您应该像在 ObjC 中那样使用 NSError
,因为 Foundation、AppKit、UIKit 等以这种方式报告他们的错误.所以与其说是语言,不如说是框架.
As Leandros suggests for handling runtime errors (like network connectivity problems, parsing data, opening file, etc) you should use NSError
like you did in ObjC, because the Foundation, AppKit, UIKit, etc report their errors in this way. So it's more framework thing than language thing.
正在使用的另一种常见模式是分隔符成功/失败块,如 AFNetworking:
Another frequent pattern that is being used are separator success/failure blocks like in 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
实例,描述错误.
Still the failure block frequently received NSError
instance, describing the error.
程序员错误:
对于程序员错误(如数组元素的越界访问、传递给函数调用的无效参数等),您在 ObjC 中使用了异常.Swift 语言似乎没有任何语言支持异常(如 throw
、catch
等关键字).但是,正如文档表明它与 ObjC 在同一运行时运行,因此您仍然可以像这样抛出 NSExceptions
:
For programmer errors (like out of bounds access of array element, invalid arguments passed to a function call, etc) you used exceptions in ObjC. Swift language does not seem to have any language support for exceptions (like throw
, catch
, etc keyword). However, as documentation suggests it is running on the same runtime as ObjC, and therefore you are still able to throw NSExceptions
like this:
NSException(name: "SomeName", reason: "SomeReason", userInfo: nil).raise()
您无法在纯 Swift 中捕获它们,尽管您可以选择在 ObjC 代码中捕获异常.
You just cannot catch them in pure Swift, although you may opt for catching exceptions in ObjC code.
问题是您是否应该为程序员错误抛出异常,或者更确切地说是像 Apple 在语言指南中建议的那样使用断言.
The questions is whether you should throw exceptions for programmer errors, or rather use assertions as Apple suggests in the language guide.
这篇关于Swift 语言中的错误处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!