//错误处理1-7
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()
网友评论