十四、错误处理

class Person {
    static var age = 0
    static func run() {}
}
Person.age = 10
Person.run()
//等价汇编代码也是一样的
Person.self.age = 10
Person.self.run()

//四个等价汇编代码也是一样的
var p0 = Person() //init()
var p1 = Person.self() //init()
var p2 = Person.init() //init()
var p3 = Person.self.init() //init()

func test(_ cls: AnyClass) {}
test(Person.self)//Person.self元类类型

//1.自定义错误
//swift中可以通过error协议自定义运行时的错误信息
enum SomeError : Error {
    case illegaArg(String)
    case outOfBounds(Int, Int)
    case outOfMemory
}
//函数内部通过throw抛出自定义Error,可能会抛出Error的函数必须加上throws声明
func divide(_ num1: Int, _ num2: Int) throws -> Int {
    if num2 == 0 {
        throw SomeError.illegaArg("0不能作为除数")
    }
    return num1 / num2
}
func test0() throws {
    print("1")
    try test1()
    print("2")
}
func test1() throws {
    print("3")
    try test2()
    print("4")
}
func test2() throws {
    print("5")
    print(try divide(200, 0)) //需要通过try调用可能会抛出Error的函数
    print("6")
}
//try test0()//1 3 5 //注释掉这行test3才会执行

//2.do-catch:可以用do-catch捕捉Error
func test3() {
    print("1")
    do {
        print("2")
        print(try divide(20, 0))
        print("3")
    }catch let SomeError.illegaArg(msg) {
        print("参数异常:",msg)
    }catch let SomeError.outOfBounds(size,index) {
        print("下标越界:","size=\(size)","index=\(index)")
    }catch SomeError.outOfMemory {
        print("内存溢出")
    }catch {
        print("其他错误")
    }
    print("4")
}
//test3()
/*
 1
 2
 参数异常: 0不能作为除数
 4
 */

do {
    try divide(20, 0)
} catch let error {//let error 去掉也行 do catch默认有error
    switch error {
    case let SomeError.illegaArg(msg):
        print("参数错误:",msg)
    default:
        print("其他错误")
    }
}
//参数错误: 0不能作为除数

//3.处理Error
//处理Error的2中方式
//(1)通过do-catch捕捉error
//(2)不捕捉Error,在当前函数增加throws声明,Error将自动抛给上层函数,如果最顶层函数(main函数)依然没有捕捉Error,那么程序将终止
func test4() throws {
    print("1")
    print(try divide(20, 0))
    print("2")
}
//try test4()
/*
 参数错误: 0不能作为除数
 1
 Playground execution terminated: An error was thrown and was not caught:
 ▿ SomeError
   - illegaArg : "0不能作为除数"
 */

func test5() throws {
    print("1")
    do {
        print("2")
        print(try divide(20, 0))
        print("3")
    } catch let error as SomeError {
        print(error)
    }
    print("4")
}
//try test5()
/*
 参数错误: 0不能作为除数
 1
 2
 illegaArg("0不能作为除数")
 4
 */

//4.try?、try!
//可以用try?、try!调用可能会抛出Error的函数,这样就不用去处理Error
func test6() {
    print("1")
    var result1 = try? divide(20, 10)
    print(result1)//Optional(2),Int?
    var result2 = try? divide(20, 0)
    print(result2)// nil
    var result3 = try! divide(20, 10)
    print(result3)//2 Int
    print("2")
}
test6()
//变量a、b是等价的
var a = try? divide(20, 0)
var b: Int?
do {
    b = try divide(20, 0)
} catch { b = nil }
print("------")
//5.rethrows表明:函数本身不会抛出错误,但调用闭包参数抛出错误,那么它会将错误向上抛
func exec(_ fn: (Int, Int) throws -> Int, _ num1: Int, _ num2: Int) rethrows {
    print(try fn(num1, num2))
}
//try exec(divide, 20, 0)
/*
 Playground execution terminated: An error was thrown and was not caught:
 ▿ SomeError
   - illegaArg : "0不能作为除数"
 */

//5.defer
/*
 defer语句:用来定义以任何方式(抛错误、return等)离开代码块前必须要执行的代码,defer语句将延迟至当前作用域结束之前执行
 */
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
 Playground execution terminated: An error was thrown and was not caught:
 ▿ SomeError
   - illegaArg : "0不能作为除数"
 */

//6.assert断言
/*
 不符合指定条件就抛出运行时错误,常用于调试阶段的条件判断
 默认情况下,swift的断言只会在debug模式下生效,release模式下会忽略.
 但增加swift flags修改断言的默认行为:
 -assert-config Release:强制关闭断言
 -assert-config Debug:强制开启断言
 */
func div(_ v1: Int, _ v2: Int) -> Int {
    assert(v2 != 0, "除数不能为0") //崩溃在这里不会往下走
    return v1 / v2
}
//print(div(20, 0))

//7.fatalError:崩溃
//如果遇到严重问题,希望结束运行程序时,可以直接使用fatalError函数抛出错误,这是无法通过do-catch捕捉的错误
func te(_ num: Int) -> Int {
    if num >= 0 {
        return 1
    }
    fatalError("num 不能小于0") //使用了fatalError就不需要写return
}
//te(-1)

//某些不得不实现、但不希望别人调用的方法,可以考虑内部使用fatalError
class Cat { required init(){} }
class Tiger : Cat {
    required init() {
        fatalError("don't call tiger.init")
    }
    init(score: Int) {}
}
var t1 = Tiger(score: 98)
//var t2 = Tiger()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值