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) 会在这里被调用,即作用域的最后。
    }
}

 

posted @ 2016-07-18 18:34  LeeGof  阅读(330)  评论(0编辑  收藏  举报