我们在Java等其他语言之都知道有错误处理 基本上都是 try和catch配对的
那么在swift中同样也有
我们首先可以定义一下自己的错误类型如下面
enum MyErrors:Error { case NOT_NUMBERIC case NO_NAME case OUT_OF_RANGE }对于异常的抛出,同样是使用throw关键字,我们使用throws来标记某个函数有异常抛出
我们来定义一个函数,用来做异常抛出
func testMyErrors(name:String,objects:[NSObject],index:Int ) <span style="color:#ff0000;">throws</span> -> Void { if name.isEmpty { <span style="color:#ff0000;">throw</span> MyErrors.NO_NAME } if objects.count < index { <span style="color:#ff0000;">throw</span> MyErrors.OUT_OF_RANGE } for object in objects { if !(object is Int) { <span style="color:#ff0000;">throw</span> MyErrors.NOT_NUMBERIC } } print("Name is \(name)") }
do { let objs:[NSObject] = [3 as NSObject,4 as NSObject] try testMyErrors(name: "",objects:objs,index: 1) } catch MyErrors.NO_NAME { print("名称为空") }我们看到使用的是 do 和 catch 当然还有try 不过try的位置跟我们所熟悉的Java代码的位置有所不同
我们这里讲name设置为空,那么就会抛出一个MyErrors.NO_NAME的异常,我们在catch中可以捕获,并做相应的处理,那么这里将会输出”名字为空“的信息
当然这是我们已经知道的可能发生的异常,我们可以精确地捕捉到,我们都知道Java中的异常处理一般是按照从小到大的范围进行网络的,最后就是最大的异常类型Exception
在swift中同样也可以,上面我们知道了名字可能为空,其他的具体还会发生什么,我们可能不太清楚,我们就可以使用下面的处理
do { let objs:[NSObject] = ["Ryoma" as NSObject,4 as NSObject] try testMyErrors(name: "Ryoma",index: 1) } catch MyErrors.NO_NAME { print("名称为空") } catch let myError as MyErrors { print(myError) } catch { print(error) }这里我们看到名字不会出现问题了,但是数组内的第一项不是Int类型的,这时肯定会出异常,我们的MyErrors.NO_NAME这个类型肯定捕获不到的,但是我们在后面定一个myError是MyErrors的类型,也就是如果发生的错误是MyErrors类型的,几遍我们上面的catch没有捕获到,我们的myError也可以捕获到,并做相应的处理。
如果说在上面的业务代码块中出现了我们无法预测的错误,不在我们所能想到的错误类型中,那也不怕,我们最后的catch会帮我们捕获到,并做处理。
最后的catch中如果我们没有对Error的名字做出什么定义的话(myError就是我们自己定义的名字)话,会有一个默认的错误类型名就是error
当然除了上面的这些错误处理同样还有一种处理,我们使用 try?形式
我们还是使用上面的异常
let objs:[NSObject] = ["Ryoma" as NSObject,4 as NSObject] try testMyErrors(name: "Ryoma",index: 1)
这样写的话因为没有catch,是无法捕获异常的,程序肯定是崩溃的
let objs:[NSObject] = ["Ryoma" as NSObject,4 as NSObject] try? testMyErrors(name: "Ryoma",index: 1)
如果我们这样写了,使用了try?的话程序就会ok的结束,如果try?后面的执行抛出了异常,那么这个异常会被忽略,如果try?的后面是具有返回值的表达式,那么这个表达式的值就是nil,如果没有异常发生,那么这个表达式的值就会被转成一个可选的值(有可能有也有可能为nil)
关于异常处理还有一个点就是defer,我个人感觉他就像是Java中的finally,就是不管这个处理中有没有异常发生,都要执行的,我们可以这里面做一些自己需要的处理,而且如果我们在一个处理中写有多个defer的话,他是按照先进后出的原则执行的
func say(){ do { let objs:[NSObject] = ["Ryoma" as NSObject,4 as NSObject] try testMyErrors(name: "Ryoma",index: 1) } catch MyErrors.NO_NAME { print("名称为空") } catch let myError as MyErrors { print(myError) } catch { print(error) } defer { print("finally will be executed even if there's an error") } defer { print("defer2") } defer { print("defer3") } } say()
输出
NOT_NUMBERIC
defer3
defer2
finally will be executed even if there's an error