16-Swift错误处理

错误处理是响应错误以及从错误中恢复的过程。swift提供了在运行对可恢复错误抛出、捕获、传送和操作的高级支持(错误处理又称之为异常处理)。
 某些操作并不能总是保证执行所有代码都可以执行或总会产生出有用的结果。可选类型用来表示值可能为空,但当执行失败的时候,通常要去了解此次失败是由什么引起的,代码就可以做出与之对应的反应。

 例如,对磁盘上的某个文件的读取操作,该任务会有多种可能失败的情形,包括指定路径下文件不存在,文件没有可读权限,或文件的编码格式不兼容。具体区分这些错误,可以让程序解决并处理对应的错误,解决不了的错误即可以报告给用于。


一、表示并抛出错误


 在swift中,错误要遵循ErrorType协议类型的值来表示。这个协议表示一种可以用做错误处理的类型。swift的枚举类型特别适合于创建一组相关错误,而枚举的关联值还可以提供额外的信息,表示错误情形的性质。

// 例如去健身房,下面是影响去健身房的情形
enum myError:ErrorType {
    case noPower    // 没体力
    case noTime      // 没时间
    case noMachine // 没器械
}


二、错误处理


 在swift中有4种错误处理方式: 把函数抛出的错误传递给调用此函数的代码、用do-catch语句处理错误、将错误作为可选类型处理、直接断言此错误根本不会发生。

  • 用throwing函数传递错误。用thows关键字来标识一个可抛出错误的函数、方法或构造器。在函数声明的参数列表之后加上throws,如果函数是有返回值的,throws关键字需要卸载箭头->的前面:
enum myError:ErrorType {
    case noPower    // 没体力
    case noTime      // 没时间
    case noMachine // 没器械
}

// 抛出异常(throwing函数)
func checkKeepFit(power:Int, time:Int, machine:Int) throws {
    // guard关键字,若守卫条件为不为真,即抛出异常。类似if语句,但不是if,guard只能用在异常处理中
    // throws 表示该函数可能抛出异常,放在返回值前面
    // throw  表示某个条件不符合的时候,抛出异常
    guard power > 0 else {
        throw MyError.noPower
    }
    guard time > 0 else {
        throw MyError.noTime
    }
    guard machine > 0 else {
        throw MyError.noMachine
    }
}

// 调用checkKeepFit函数(即在此函数中处理异常)
func goToKeepFit(power:Int, time:Int, machine:Int) {
    /**  异常的处理
    try!和try?: 用于标记一个被调用的抛出对象的方法,你等于告诉编译器这个错误永远不会发生,并且你也不需要捕获它。
    try!: 如果该语句本身产生错误(error),应用程序会自动停止执行,那么你就要开始调试了;
    try?: 如果该语句本身产生了错误(error),应用程序也不会停止执行;
    */
    try? checkKeepFit(power, time: time, machine: machine)
    
    // 如果上面使用try!,那么应用程序会报错
    print("---------")
}

// 函数调用
goToKeepFit(0, time: 1, machine: 1)
输出结果:
---------
  • do-catch处理错误。即用do-catch语句运行一段闭包代码来做错误处理,如果do语句中的代码抛出了一个错误,则这个错误会与catch语句做匹配来决定哪条语句处理:
// 调用checkKeepFit函数(即在此函数中处理异常)
func goToKeepFit(power:Int, time:Int, machine:Int) {
    // try 捕获异常
    do {
        try checkKeepFit(power, time: time, machine: machine);
    } catch MyError.noPower {
        print("没有体力");
    } catch MyError.noTime {
        print("没有时间");
    } catch MyError.noMachine {
        print("没有器材");
    } catch {   // 不能少这个,如果缺少,那么上面try会出错!!!
        print("未知异常");
    }
}

goToKeepFit(0, time: 1, machine: 1)

输出结果:
没有体力
  • 将错误转换成可选值。可以使用try?通过将其转换成一个可选值来处理错误,如果在评估try?表达式时一个错误被抛出,那么这个表达式就是nil
enum MyError:ErrorType {
    // 负数
    case negativeNumer
}

// 判断是否为正数
func isPlus(a:Int) throws -> Int {
    // 如果a大于0,则程序继续向下执行  
    // 否则,就会是抛出异常
    guard a > 0 else {  
        throw MyError.negativeNumer
    }
    
    return a
}

// 如果`isPlus`抛出异常,那么x值就是为`nil`
// 否则就是该函数的返回值
let x = try? isPlus(10)
// 注意: x自动推断是为可选类型
print(x!)

// 这里就是保证y肯定就是不为负数
let y:Int
do {
    y = try isPlus(-1)
} catch {
    y = 0
}
print(y)
输出结果:
10
0
  • 使错误传递失败。当知道某个throwing函数在实际运行中是不会抛出错误的,那么就可以在表达式前面添加try!来使错误传递失败,但实际上抛出了错误,就会得到运行时错误:
例如使用`loadImage(_:)`函数,该函数即是从给定路径中加载图片资源,如果图片不能被加载则会抛出一个错误。而图片和应用是绑定在一起的,应用程序运行时不会有错误被抛出,所以可以让错误传递失败
// 该图片地址是虚拟的
let photo = try! loadImage("./User/EndEvent/head.png")


三、指定清理操作


 可以使用defer语句在代码执行到要离开当前代码段之前,再去执行一段代码。该代码能够执行必要清理操作,不管是以何种方式离开当前的代码段(不论是抛出错误离开还是return或是break语句)。

// 文件处理
func processFile(fileName:String) throws {
    // 判断文件是否存在,存在才做具体操作
    if exists(fileName) {
        // 打开文件
        let file = open(fileName)
        defer { // 这就可以保证在文件描述符在退出后被关闭
            close(file)
        }
        
        while let line try file.readline() {
            // 对应处理文件
        }
        
        // 处理完成,将关闭文件描述符
        close(file)
    }
}

注意: 即是没有涉及到错误处理代码,也可以使用defer语句。


注:xcode7.3环境

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容