** 异常的抛出与传递
swfit中,所有的错误和异常都由Error协议来指定。
开发者可以编写自定义的枚举类型,使其遵守Error协议来描写所需求的异常类型
函数中产生的异常只能在函数内部解决,开发者也可以使用throws关键字将此函数声明为可抛异常函数,此类声明则允许开发者在函数外解决函数内部抛出的异常
** 异常的捕获与处理
系统为我们提供了三种异常处理的方法:
<1> 使用do-catch结构来捕获处理异常、将异常映射为optional值,终止异常传递
<2> 使用try?来调用函数可以将异常映射为Optional值
<3> 使用try!来强制终止异常的传递
do-catch:do-catch结构是swift语言中处理异常最常用的方法,开发者需要将可能抛出的异常的代码放入do结构中,如果这部分代码中有抛出异常,则会从catch块中寻找对应的异常类型,如果找到对应的,则会执行此catch块中的异常处理代码.
使用do-catch处理异常可以根据异常类型分别提供处理方案,保证代码的健壮与可控性。
try?:有些时候开发者可能并不关心产生异常的类型和原因,只需要知道有没有产生异常,对于这种情况,使用do-catch结构会显得十分繁琐冗余。
try?可以将异常映射为optional值,如果函数正常运行,没有抛出异常,则正常返回,如果函数执行出错,抛出了异常,则会返回optional值nil。
使用try?调用函数可以将异常映射为optional值
try!:当开发者能够保证此函数一定不会抛出异常时,便可以使用try!来强制终止异常的传递,然而这么做有一定风险,如果这个函数真的抛出了异常,则会产生运行时错误
** 延时执行结构
延时执行结构:延时构造语句lazy的作用是降低复杂类实例构造时所消耗的时间,swift语言中还提供了一种延时执行结构,defer{}
作用:在函数中使用延执行结构可以保证结构中的代码块始终在函数要结束时执行
使用场景:延时执行结构常被用来释放函数中所使用的一些资源和关闭文件等操作
延时执行结构存在的意义:
开发者会疑惑,如果想让一部分代码在函数结束前才执行,那么直接将它放在函数最后不就行了嘛?实际情况并非如此:
在函数中,经常会由于特殊情况提前被break(中断)或者return(返回),或者一个复杂函数很可能会因为抛出异常而被中断,这些情况会造成函数的结束。
使用延时执行语句可以保证无论函数因为何种原因结束,在结束前都会执行延时结构块中代码
//使用throws关键字,以及使用try?做异常处理
//一个开水阀出水的场景,假设水滴的个数,n = 0 水阀坏了,n < 5停水了, n > 5 水阀坏了
//定义异常
enum OpenWaterError : Error{
case NoWater //停水了
case FMBroken //水阀坏了
}
class OpenWaterWork{
//使用throws关键字将此函数声明为可抛异常函数
func openWater(droplets : Int)throws {
if droplets == 0 {
throw OpenWaterError.FMBroken
}
else if droplets > 0, droplets < 5{
throw OpenWaterError.NoWater
}
else{
print("The Water is OK!")
}
}
}
//使用throws,与do-catch结构
//定义异常
enum MyError:Error{
case DesTroyError
case NormalError
case SimpleError
}
class MyErrorWork{
//自定义一种异常类型,之后在代码中通过throw关键字进行异常的抛出
func useThrowToError(isThrow:Bool)throws{
if isThrow {
print("throw MyError.DesTroyError, finished!")
throw MyError.DesTroyError
}
else{
print("this is no error!")
}
}
func useTryError()throws{
print("This is no error, in use try! error.")
}
}
//延时执行结构
class DelayedExecution{
func temError()throws -> Void{
defer{
print("Delayed Execution Last Work!")
}
print("handle")
//抛出异常
throw MyError.DesTroyError
}
}
class ErrorThrow: NSObject {
//使用throws,与do-catch结构
func useMyErrorWork(){
let myError = MyErrorWork()
//使用do-catch结构去处理抛出的异常
do {
try myError.useThrowToError(isThrow: true)
} catch MyError.DesTroyError {
print("DesTroyError!")
}catch MyError.NormalError{
print("NormalError!")
}catch MyError.SimpleError{
print("SimpleError!")
}catch{
print("other error")
}
/*打印信息:
throw MyError.DesTroyError, finished! 在MyErrorWork中函数抛出的异常
DesTroyError! 在do-catch结构中处理异常所打印的信息
*/
}
//使用throws关键字,以及使用try?做异常处理
func useErrorInOpenWater(){
let opt = OpenWaterWork()
//直接这样调用只写了throws的函数,函数中值throw抛出了异常,但没有使用try等去处理异常会报错
//opt.openWater(droplets: 1) //Call can throw, but it is not marked with 'try' and the error is not handled
let op_result: ()? = try?opt.openWater(droplets: 1)
if op_result == nil{
print("执行失败")
}else{
print("执行成功")
}
/* 打印的信息:
执行失败 op_result = nil此时打印了这个结果,因为openWater函数里有抛出异常,而可选值返回的是nil
*/
//注意:返回值Void并不是nil,Void是空类型,nil是Optional类型中的一种特殊值。由于try?语法的存在,结合if-let语句,开发者可以写出十分飘逸的异常处理代码。我们可以把代码优化写,如下这样写:
if let _ = try?opt.openWater(droplets: 1){
print("Successed")
}else{
print("Failed")
}
/* 打印的信息:
Failed if的判断条件不为真,因此进入else,因为optional返回的是nil,此时openWater函数有异常抛出
*/
}
//使用try!
func useErrorTry(){
let myError = MyErrorWork()
//此时调用的函数如果产生了异常,就会发生运行时错误,此处使用了一个throws的函数直接报错了
//try! myError.useThrowToError(isThrow: true)
//报错:Thread 1: Fatal error: 'try!' expression unexpectedly raised an error: SwiftCode.MyError.DesTroyError
try! myError.useTryError() //此时终止了异常的传递
print("This is use try! in useErrorTry.")
/* 打印信息:
This is no error, in use try! error. 函数useTryError()被执行时打印的
This is use try! in useErrorTry. try!强制后,打印的后面一句print
*/
}
//延时执行结构
func delayedExecution(){
let de = DelayedExecution()
//使用延时执行结构
//这里不处理异常,同样会报错
//try de.temError() //Errors thrown from here are not handled
if let _ = try? de.temError(){
print("try succeded in delayed execution!")
}
else{
print("try failed in delayed execution!")
}
/* 打印信息
handle //defer延时结构后面的代码先被执行了
Delayed Execution Last Work! //defer结构中的print代码在函数temError()中最后执行
try failed in delayed execution! //temError()抛出了一个异常,optional选择结构返回了nil,执行了else打印的信息
*/
}
}