错误处理
2019-07-16 本文已影响0人
曹来东
错误类型
- 语法错误(编译报错)
- 逻辑错误
- 运行时错误(可能会导致闪退,一般也叫做异常)
自定义错误
- Swift中可以通过
Error
协议自定义运行时的错误信息 - 函数内部通过
throw
抛出自定义Error
,可能会抛出Error
的函数必须加上throws
声明 - 需要使用try调用可能会抛出Error的函数
enum SomeError: Error {
case illegalArg(String)
case outOfBounds(Int, Int)
case outOfMemory
}
func divide(_ num1: Int, _ num2: Int)throws -> Int {
if num2 == 0 {
throw SomeError.illegalArg("0不能作为除数")
}
return num1 / num2
}
enum SomeError: Error {
case illegalArg(String)
case outOfBounds(Int, Int)
case outOfMemory
}
func divide(_ num1: Int, _ num2: Int)throws -> Int {
if num2 == 0 {
throw SomeError.illegalArg("0不能作为除数")
}
return num1 / num2
}
var result = try divide(20, 11)
do-catch
- 可以使用
do-catch
捕捉Error
- 抛出
Error
后,try
下一句直到作用域结束的代码都将停止运行
enum SomeError: Error {
case illegalArg(String)
case outOfBounds(Int, Int)
case outOfMemory
}
func divide(_ num1: Int, _ num2: Int)throws -> Int {
if num2 == 0 {
throw SomeError.illegalArg("0不能作为除数")
}
return num1 / num2
}
func test() {
print(1111)
do {
print(2222)
print(try divide(20, 0))
print(33333)
} catch let SomeError.illegalArg(msg) {
print("参数异常",msg)
} catch let SomeError.outOfBounds(size, index) {
print("下标越界:","size = \(size)","index = \(index)")
} catch let SomeError.outOfMemory {
print("内存溢出")
} catch {
print("其他错误")
}
print(44444)
}
test()
//打印结果
1111
2222
参数异常 0不能作为除数
44444
处理Error的两种方式
- 通过
do-catch
捕捉Error
- 不捕捉
Error
,在当前函数增加throws
声明.Error
将自动抛给上层函数.如果顶层函数(main函数)依然没有捕捉到 Error,那么程序将终止
enum SomeError: Error {
case illegalArg(String)
case outOfBounds(Int, Int)
case outOfMemory
}
func divide(_ num1: Int, _ num2: Int)throws -> Int {
if num2 == 0 {
throw SomeError.illegalArg("0不能作为除数")
}
return num1 / num2
}
func test() throws {
print(1111)
print(try divide(20, 0))
print(22222)
}
try test()
//打印结果
//1111
//Fatal error: Error raised at top level:
enum SomeError: Error {
case illegalArg(String)
case outOfBounds(Int, Int)
case outOfMemory
}
func divide(_ num1: Int, _ num2: Int)throws -> Int {
if num2 == 0 {
throw SomeError.illegalArg("0不能作为除数")
}
return num1 / num2
}
func test() throws {
print(1111)
do {
print(222)
print(try divide(20, 0))
print(3333)
} catch let error as SomeError {
print(error)
}
print(444)
}
try test()
//打印结果
1111
222
illegalArg("0不能作为除数")
444
try? try!调用可能会抛出Error
的函数,这样就不用去处理Error
enum SomeError: Error {
case illegalArg(String)
case outOfBounds(Int, Int)
case outOfMemory
}
func divide(_ num1: Int, _ num2: Int)throws -> Int {
if num2 == 0 {
throw SomeError.illegalArg("0不能作为除数")
}
return num1 / num2
}
func test() {
print(111)
var result1 = try? divide(20, 10)//optional(2) Int?
var result2 = try? divide(20, 0) //nil
var result3 = try! divide(20, 10) //2 Int
print(2)
}
test()
//111
//2
a b是等价的
var a = try? divide(20, 10)
var b : Int?
do {
b = try divide(20, 10)
} catch let error as SomeError {
print(error)
}
rethrows
- rethrows表明: 函数本身不会抛出错误,但调用闭包参数抛出错误,那么他会将错误向上抛
enum SomeError: Error {
case illegalArg(String)
case outOfBounds(Int, Int)
case outOfMemory
}
func divide(_ num1: Int, _ num2: Int)throws -> Int {
if num2 == 0 {
throw SomeError.illegalArg("0不能作为除数")
}
return num1 / num2
}
func exec(_ fn: (Int , Int) throws -> Int, _ num1: Int,_ num2: Int) rethrows {
print(try fn(num1, num2))
}
//Fatal error: Error raised at top level:
try exec(divide(_:_:), 20, 0)
defer
-
defer
语句: 用来定义以任何方式(抛错误,return等)离开代码快前必须要执行的代码 -
defer
语句将延迟至当前作用域结束之前执行 -
defer
语句的执行顺序与定义顺序相反
enum SomeError: Error {
case illegalArg(String)
case outOfBounds(Int, Int)
case outOfMemory
}
func divide(_ num1: Int, _ num2: Int)throws -> Int {
if num2 == 0 {
throw SomeError.illegalArg("0不能作为除数")
}
return num1 / num2
}
func open(_ fileName: String) -> Int {
print("open")
return 0
}
func close(_ file: Int) {
print("close")
}
func processFile(_ filename: String) throws {
let file = open(filename)
defer {
close(file)
}
//使用file
//...
try divide(20, 0)
//close将会在这里调用
}
try processFile("test.txt")
//open
//close
//Fatal error: Error raised at top level:
func fn1() {
print("fn1")
}
func fn2() {
print("fn2")
}
func test() {
defer {
fn1()
}
defer {
fn2()
}
}
test()
//打印
fn2
fn1