事情在Swift 2中有所改变,因为有一个新的错误处理机制,它在某种程度上更类似于异常但细节不同。
1.指示错误的可能性
如果函数/方法想要表明它可能会引发错误,它应该包含这样的throws关键字
func summonDefaultDragon() throws -> Dragon
注意:没有指定函数实际可以抛出的错误类型。这个声明简单地声明函数可以抛出任何类型的实现ErrorType的实例或者根本不抛出。
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) }
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 defer vs traditional try-catch-finally语法。
>异常处理通常在异常路径中比在成功路径中产生更高的执行时间。这不是Swift 2.0错误的情况,其中成功路径和错误路径成本大致相同。
>所有错误抛出代码必须声明,而异常可能已从任何地方抛出。所有错误在Java命名法中都是“checked exceptions”。但是,与Java相反,您不指定可能抛出的错误。
> Swift异常与ObjC异常不兼容。你的do-catch块不会捕获任何NSException,反之亦然,因为你必须使用ObjC。
> Swift异常与返回false(用于Bool返回函数)或nil(用于AnyObject返回函数)和传递带有错误详细信息的NSErrorPointer的Cocoa NSError方法约定兼容。
作为一个额外的语法糖,以减轻错误处理,还有两个概念
> deferred actions(使用defer关键字),它让你实现与Java / C#/ etc中finally块相同的效果
>保护语句(使用保护关键字),如果/ else代码比正常的错误检查/信令代码更少。
Swift 1
运行时错误:
由于Leandros建议处理运行时错误(如网络连接问题,解析数据,打开文件等),你应该使用像你在ObjC中的NSError,因为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中使用了异常。 Swift语言似乎没有任何语言支持异常(如throw,catch,etc关键字)。但是,由于文档建议它运行在与ObjC相同的运行时,因此你仍然能够抛出像这样的NSExceptions:
NSException(name: "SomeName",reason: "SomeReason",userInfo: nil).raise()
你只能在纯Swift中捕获它们,尽管你可以选择在ObjC代码中捕获异常。
问题是你是否应该抛出程序员错误的异常,或者使用苹果在语言指南中建议的断言。