18.错误处理
错误处理(Error handling)是响应错误以及从错误中恢复的过程。Swift 提供了在运行时对可恢复错误的抛出、捕获、传递和操作的一流支持。
某些操作无法保证总是执行完所有代码或总是生成有用的结果。可选类型可用来表示值缺失,但是当某个操作失败时,最好能得知失败的原因,从而可以作出相应的应对。
1.表示并抛出错误
- 在 Swift 中,错误用符合ErrorType协议的类型的值来表示。这个空协议表明该类型可以用于错误处理。
- Swift 的枚举类型尤为适合构建一组相关的错误状态,枚举的关联值还可以提供错误状态的额外信息。
- 抛出错误使用throw关键字。
/** 服务端请求结果 - RequestDataResultSuccess: 请求成功 - RequestDataResultTimeOut: 超时 - RequestDataResultNoNet: 无网络 - RequestDataResultOther: 其他 */ enum RequestDataResult: ErrorType { case RequestDataResultSuccess; case RequestDataResultTimeOut; case RequestDataResultNoNet; case RequestDataResultOther; } throw RequestDataResult.RequestDataResultSuccess;
2.处理错误
- Swift 中有4种处理错误的方式。可以把函数抛出的错误传递给调用此函数的代码、用do-catch语句处理错误、将错误作为可选类型处理、或者断言此错误根本不会发生。
enum RequestDataResult: ErrorType { case RequestDataResultSuccess; case RequestDataResultTimeOut; case RequestDataResultNoNet; case RequestDataResultOther; } class DataRequestHelper { //1.用 throwing 函数传递错误 //为了表示一个函数、方法或构造器可以抛出错误,在函数声明的参数列表之后加上throws关键字。一个标有throws关键字的函数被称作throwing 函数。如果这个函数指明了返回值类型,throws关键词需要写在箭头(->)的前面。 func getDataFromServer(name: String) throws -> String { //guard关键字可以看看这篇介绍:http://www.jianshu.com/p/3a8e45af7fdd guard name == "Gof" else { //变量不符合条件时,抛出异常 throw RequestDataResult.RequestDataResultOther; } guard name == "LGF" else { throw RequestDataResult.RequestDataResultTimeOut; } guard name == "LeeGof" else { throw RequestDataResult.RequestDataResultNoNet; } return "This is Jim"; } func test() throws { //调用的时候前面加了try关键字 try getDataFromServer("abc"); } } //2.用 Do-Catch 处理错误 //如果在do子句中的代码抛出了一个错误,这个错误会与catch子句做匹配,从而决定哪条子句能处理它。 var dataRequestHelper = DataRequestHelper(); do { try dataRequestHelper.getDataFromServer("Gof"); } catch RequestDataResult.RequestDataResultOther { print("Invalid Name.") } catch RequestDataResult.RequestDataResultTimeOut { print("Time Out.") } catch RequestDataResult.RequestDataResultNoNet { print("Net error.") } //3.将错误转换成可选值 //可以使用try?通过将错误转换成一个可选值来处理错误。如果在评估try?表达式时一个错误被抛出,那么表达式的值就是nil。 var result = try? dataRequestHelper.getDataFromServer("LGF"); //4.禁用错误传递 //如果确认 throwing 函数实际上在运行时是不会抛出错误的,可以在表达式前面写try!来禁用错误传递,这会把调用包装在一个不会有错误抛出的运行时断言中。如果真的抛出了错误,将会得到一个运行时错误。 //var result2 = try! dataRequestHelper.getDataFromServer("Hi"); //运行时错误
3.指定清理操作
- 可以使用defer语句在即将离开当前代码块时执行一系列语句。该语句让你能执行一些必要的清理工作,不管是以何种方式离开当前代码块的——无论是由于抛出错误而离开,还是由于诸如return或者break的语句。
//TODO:伪代码示例 func processFile(filename: String) throws { if exists(filename) { let file = open(filename); defer { close(file); } while let line = try file.readline() { // 处理文件。 } // close(file) 会在这里被调用,即作用域的最后。 } }
无善无恶心之体,
有善有恶意之动,
知善知恶是良知,
为善去恶是格物。