目录
错误分析
一、使用方式
如果函数内有throw,函数声明必须使用throws关键字声明,也就是说 thorw 和 throws 必须同时使用。
func readFile(at path: String) throws -> String {
guard path != "" else {
throw FileError.fileNotFound
}
// 假设成功读取文件
return "File content"
}
调用有三种方式
1、使用try的时候,要么使用do catch捕捉错误,要么继续向上抛
// 捕获
func test(){
do {
let content = try readFile(at: "")
print(content)
} catch FileError.fileNotFound {
print("File not found!")
} catch FileError.insufficientPermissions {
print("Insufficient permissions!")
} catch {
print("An unknown error occurred: \(error)")
}
}
// 继续向上抛
func test() throws {
try readFile(at: "")
}
2、使用try?的时候,如果函数内抛出错误,返回nil
let content1 = try? readFile(at: "")
print(content1 ?? "发生了错误")
3、try!: 断言不会抛出错误,如果出错则程序崩溃。
let content2 = try! readFile(at: "")
print(content1)
二、小码哥讲解
/// 一、错误分析
func errorExPlain()->Void {
//Swift中可以通过Error协议自定义运行时的错误信息
enum SomeError:Error{
case illegalArg(String)
case outOfBands(Int,Int)
case outOfMemory
}
//函数内部通过throw抛出自定义Error,可能会抛出Error的函数必须加上throws声明
func divide(_ num1:Int,_ num2:Int) throws->Int{
if num2 == 0 {
throw SomeError.illegalArg("0不能作为除数")
//print("devide")//Code after 'throw' will never be executed
}
return num1/num2
}
//1、可以使用do-catch捕捉Error
do{
print("--------1---------")
do {
//需要使用try调用可能会抛出Error的函数
try print(divide(10, 0))
} catch {
//默认就有一个error存在
print("抛出的error:",error)
}
}
//2、catch let 绑定
do{
print("--------2---------")
do {
print("1")
print(try divide(10, 0))
//抛出Error后,try下一句直到作用域结束的代码都将停止运行
print("2")
} catch let SomeError.illegalArg(msg) {
print("msg:",msg)
} catch let SomeError.outOfBands(x,y){
print("x is",x,"y is ",y)
}catch SomeError.outOfMemory{
print("内存溢出")
}catch{
print("other")
}
print("3")
}
//3、
do{
print("----------3---------")
do {
print(try divide(20, 0))
} catch let error {
switch error {
case let SomeError.illegalArg(msg):
print("参数错误:", msg)
default:
print("其他错误")
}
}
}
//4、
do{
print("----------4---------")
do {
print(try divide(20, 0))
} catch is SomeError {
print("SomeError:")
}catch{
print("other")
}
}
//5、
do{
print("---------5----------")
do {
print("1")
print(try divide(20, 0))
print("2")
} catch let error as SomeError {
print("error:",error)
}catch{
print("other")
}
print("3")
}
//6、
do{
print("---------6----------")
/**
处理Error的2种方式
通过do-catch捕捉Error
不捕捉Error,在当前函数增加throws声明,Error将自动抛给上层函数
如果最顶层函数(main函数)依然没有捕捉Error,那么程序将终止
*/
func test () throws {
print("1")
print(try divide(20, 0))
print("2")
}
func test2() throws {
try test()
}
do {
try test2()
} catch let error {
print("error:",error)
}
}
//7、try?、try!
do{
print("---------7----------")
//可以使用try?、try!调用可能会抛出Error的函数,这样就不用去处理Error
print(try?divide(10, 1))
print(try?divide(10, 0))
print(try!divide(20, 1))
// print(try!divide(20, 0))//nil强制解包会报错
//try?相当于下面的逻辑
let b:Int?
do {
b = try divide(10, 0)
} catch {
b = nil
}
print(b)
}
}
rethrows
一、使用方式
1、函数本身不会抛出错误,但闭包参数会抛出错误,闭包抛出的错误可以在函数内调用时进行捕获。
func execute(task: () throws -> Void) {
// 需要捕捉错误
do{
try task()
} catch FileError.fileNotFound {
print("File not found!")
} catch FileError.insufficientPermissions {
print("Insufficient permissions!")
} catch {
print("An unknown error occurred: \(error)")
}
}
// 调用
execute(task:{
throw FileError.unknown
})
2、如果不在函数内进行捕获,可以将错误向上抛出,这时就可以不使用do…catch,而是需要在声明处使用rethrows关键字。
因为向上抛出了,所以调用外部函数时进行错误捕获。
func execute(task: () throws -> Void) rethrows {
try task()
}
// 调用
do {
try execute(task:{
throw FileError.unknown
})
} catch FileError.fileNotFound {
print("File not found!")
} catch FileError.insufficientPermissions {
print("Insufficient permissions!")
} catch {
print("An unknown error occurred: \(error)")
}
rethrows跟throws的作用一样,只是rethrows表明错误是由闭包参数抛出的
二、小码哥讲解
/// 二、rethrows
func rethrowsUse(){
struct MyError:Error{
var msg:String
}
func divide(_ num1:Int,_ num2:Int) throws->Int{
if num2 == 0 {
throw MyError(msg: "除数不能为0")
}
return num1/num2
}
do {
print(try divide(10, 0))
} catch let error as MyError {
print(error.msg)//除数不能为0
}catch{
print("other error")
}
//rethrows表明:函数本身不会抛出错误,但调用闭包参数抛出错误,那么它会将错误向上抛
// rethrows 跟 throws的作用相同 只是表明这个错误不是函数本身抛出的
func exec(_ fn:(Int,Int) throws->Int,_ num1:Int,_ num2:Int) rethrows->Int{
return try fn(num1,num2)
}
do {
print(try exec(divide, 10, 0))
} catch let error {
print(error)//MyError(msg: "除数不能为0")
}
}
defer的用法
/// 三、defer的用法
func deferUse() -> Void {
class MyError:Error{
var msg:String
var code:Int
init(msg:String,code:Int) {
self.msg = msg
self.code = code
}
}
func divide(_ num1:Int,_ num2:Int) throws->Int{
if num2 == 0{
throw MyError(msg:"除数不能为0", code:3)
}
return num1 / num2
}
do {
print(try divide(10, 0))
} catch let error as MyError {
print(error.msg,error.code)
}catch{
print("other error")
}
print("-----------------")
func open(_ fileName:String){
print("打开\(fileName)")
}
func close(_ fileName:String){
print("关闭\(fileName)")
}
func process(_ fileName:String) throws{
open(fileName)
//使用file过程中
//...
print(try divide(10, 0))
//divide抛错之后会导致close无法执行 造成内存泄漏
close(fileName)
}
func processFile(_ fileName:String) throws{
open(fileName)
// 在Swift中,defer语句用于在当前作用域退出之前执行一段代码。这无论是由于正常的返回还是由于异常抛出,defer中的代码都会被执行。
// 这在资源管理、清理操作和确保某些操作总是执行时非常有用。
defer{
close(fileName)
}
//使用file过程中
//...
print("执行中...")
print(try divide(10, 0))
}
do {
print(try process("myFile"))
} catch let error as MyError {
print(error.msg,error.code)
}catch{
print("other error")
}
print("-----------------")
do {
print(try processFile("myFile"))
} catch let error as MyError {
print(error.msg,error.code)
}catch{
print("other error")
}
print("-----------------")
//当有多个defer语句时,它们的执行顺序与定义顺序相反
func fn1() { print("fn1") }
func fn2() { print("fn2") }
func test() {
defer { fn1() }
defer { fn2() }
}
test()
}
assert的使用
/// 四、assert的使用
func assertUse(){
/**
很多编程语言都有断言机制:不符合指定条件就抛出运行时错误,常用于调试(Debug)阶段的条件判断
默认情况下,Swift的断言只会在Debug模式下生效,Release模式下会忽略
增加Swift Flags修改断言的默认行为
Other Swift Flags
-assert-config Release:强制关闭断言
-assert-config Debug:强制开启断言
*/
func divide(v1:Int,v2:Int)->Int{
//false触发断言
assert(v2 != 0,"除数不能为0")
return v1 / v2
}
print(divide(v1: 20, v2: 0))
}
fatalErro的使用
/// 五、fatalErro的使用
func fatalErrorUse() -> Void {
/**
如果遇到严重问题,希望结束程序运行时,可以直接使用fatalError函数抛出错误(这是无法通过do-catch捕捉的错误)
使用了fatalError函数,就不需要再写return
*/
func test(_ num: Int) -> Int {
if num >= 0 {return 1}
fatalError("num不能小于0")
}
// print(test(-1))
/**
在某些不得不实现、但不希望别人调用的方法,可以考虑内部使用fatalError函数
*/
class Person {
required init() {}
}
class Student : Person {
required init() {
fatalError("don't call Student.init")
}
init(score: Int) {}
}
let stu1 = Student(score: 98)
let stu2 = Student()
print(stu1,stu2)
}
行者常至,为者常成!