一.自定义错误类型,使用do catch处理可能抛出的异常

// 1.枚举必须是遵守Error协议,如果换成类也必须要遵守Error
enum SomeError: Error {
    case illegalArg(String)
    case outOfBounds(Int, Int)
    case outOfMemory
}

// 2.throws 和 throw 注意区别 throws函数的声明
func divide(num1: Int, num2: Int) throws -> Int{
    if num2 == 0 {
        throw SomeError.illegalArg("0不能作为除数")
    }
    return num1/num2
}
// 3.调用可能抛出错误的方法,使用do catch处理
func test() {
    print(0)
    do {
        print(1)
        let res = try divide(num1: 200, num2: 0)
        print(res)
        print(2)
    } catch let SomeError.illegalArg(msg) {
        print("参数异常:\(msg)")
    } catch let SomeError.outOfBounds(size, index) {
        print("下标越界:size=\(size), index=\(index)")
    } catch SomeError.outOfMemory {
        print("内存溢出")
    } catch {
        print("其他错误")
    }
    print(3)
}

注意点:

二.不捕捉Error,在当前函数增加throws声明,Error将自动抛给上层函数,如果最顶层函数(main函数)依然没有捕捉Error,那么程序将终止

func test0() {
    // 强制调用,如果出错程序就闪退
    try! test1()
    
    // 或者
    do {
        try test1()
    }catch {
        
    }
}
// 如果自己不处理,那么往上抛
func test1() throws{
    try test2()
}
// 如果自己不处理,那么往上抛
func test2() throws {
    let res = try divide(num1: 200, num2: 0)
    print(res)
}

三.使用try? try!调用可能会抛出Error的函数,这样就不用处理Error

func testTry() {
    let res1 = try? divide(num1: 20, num2: 10)
    print(res1) // Optional(2)
    let res2 = try? divide(num1: 20, num2: 0)
    print(res2) // nil
    let res3 = try! divide(num1: 20, num2: 10)
    print(res3) // 2
    let res4 = try! divide(num1: 20, num2: 0)
    print(res4) // 会闪退 
    //Fatal error: 'try!' expression unexpectedly raised an error: TEST_Swift.SomeError.illegalArg("0不能作为除数"): file......
}

try!一定要慎用

try? 的本质

var a = try? divide(num1: 20, num2: 10)
// 这两种写法,都是一样的效果
var b: Int?
do {
    b = try divide(num1: 20, num2: 10)
} catch { b = nil }

四:rethrows关键字

表示: 函数本身不会抛出错误,单调用闭包参数抛出错误,那么它会将错误向上抛

示例

func exec(_ fn: (Int, Int) throws -> Int, num1: Int, num2: Int) rethrows {
    print(try fn(num1,num2))
}

// try? exec(divide, num1: 20, num2: 0)
try! exec(divide, num1: 20, num2: 0)

说白了,rethrows这个关键字告诉我们,这个方法的错误,是由传过来的参数(一般是闭包或者函数)造成的,不是我本身的原因

示例 ??

public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T