Swift:错误处理专题

1. assert和precondition

//: Playground - noun: a place where people can play

import UIKit

// 下面的三个用于调试,在真机上不起作用
assert(1>0) // 必须满足括号里面的逻辑,不然停止
assert(1>0, "Error") // 必须满足括号里面的逻辑,不然停止并报错
assertionFailure("Error!") // 直接停止并报错

// 下面的三个和assert作用一模一样,在真机上也起作用
precondition(1>0)
precondition(1>0, "Error")
fatalError("Error")

2. throw,throws,系统自带的协议Error

import UIKit

// 自动贩卖机
class VendingMachine {

    struct Item {
        enum ItemType: String {
            case Water
            case Cola
            case Juice
        }

        let type: ItemType
        let price: Int
        var count: Int
    }

    // 继承一个错误处理的类,名字叫Error
    enum ItemError: Error {
        case NoSuchItem
        case NotEnoughMoney(Int)
        case OutOfStock
        case OtherError
    }

    private var items = ["Mineral Water" : Item(type: .Water, price:2, count:10),
                         "Coca Cola" : Item(type: .Cola, price: 3, count: 5),
                         "Orange Juice" : Item(type: .Juice, price: 5, count: 3)]

    func vend(itemName: String, money: Int, count: Int) throws -> Int { // 如果有错误就抛出,没有就正常运行
        guard let item = items[itemName] else {
            throw ItemError.NoSuchItem // 程序结束,抛出异常
        }
        guard money >= item.price else {
            throw ItemError.NotEnoughMoney(item.money) // 并携带一个返回值,是应付单价
        }
        guard item.count > 0 else {
            throw ItemError.OutOfStock
        }
        guard count > 0 else {
            throw ItemError.OtherError
        }
        dispenseItem(itemName: itemName)
        return money - item.price * item.count
    }

    private func dispenseItem(itemName: String) {
        items[itemName]?.count -= 1
        print("Enjoy your \(itemName)")
    }
}

3.try、do-catch、catch let ... as

对于一个这样的函数

func vend(itemName itemName: String, money: Int) throws -> Int{
        
        guard let item = items[itemName] else{
            throw VendingMachine.ItemError.NoSuchItem
        }
        
        guard money >= item.price else{
            throw VendingMachine.ItemError.NotEnoughMoney(item.price)
        }
        
        guard item.count > 0 else{
            throw VendingMachine.ItemError.OutOfStock
        }
        
        dispenseItem(itemName: itemName)
        
        return money - item.price
    }

自定义的错误如下

enum ItemError: Error, CustomStringConvertible{         //swift 3
    case NoSuchItem
    case NotEnoughMoney(Int)
    case OutOfStock
    
    var description: String{
        switch self {
        case .NoSuchItem:                return "Not Such Item"
        case .NotEnoughMoney(let price): return "Not Enough Money. " + String(price) + " Yuan needed."
        case .OutOfStock:                return "Out of Stock"
        }
    }
}

现在我们处理异常的方式可以有如下几种

Ps:可以抛出异常的函数类似于可选性,不能直接调用,因此要么用try,要么用do-catch

<1> try! 表示强制解析,确认一定没有异常,慎用!

pocketMoney = try! machine.vend(itemName: "Coca Cola", money: pocketMoney)

<2> try?表示如果没有异常就正常进行,不然就返回nil

try? machine.vend(itemName: "Coca Cola", money: pocketMoney)

<3> do-catch,do里面是正常逻辑,catch可以指定具体的错误类型,但是建议在最后加上一个catch什么也不接的,这样可以捕获所有异常,catch中可以也可以用let捕获错误里带有的值

do{
    pocketMoney = try machine.vend(itemName: "Coca Cola", money: pocketMoney)
    print(pocketMoney,"Yuan left")
}
catch VendingMachine.ItemError.NoSuchItem{
    print("No Such Item")
}
catch VendingMachine.ItemError.NotEnoughMoney(let price){ // 这里可以获取抛出异常时自己带有的值
    print("Not Enough Money." , price , "Yuan needed.")
}
catch VendingMachine.ItemError.OutOfStock{
    print("Out of Stock")
}
catch{
    print("Error occured during vending.")
}

<4> 如果想输出error的具体信息或者对error进行操作,也可以用catch let ... as语句,将错误转成自己定义的类型,并进行一定的操作

do{
    pocketMoney = try machine.vend(itemName: "Coca Cola", money: pocketMoney)
    print(pocketMoney,"Yuan left")
}
catch let error as VendingMachine.ItemError{
    print(error)
}
catch{
    print("Error occured during vending.")
}

4. defer关键字

写在函数里,一个函数里可以有多个,当且仅当函数退出作用域的时候运行,即正常return,或者抛出异常。

如果一个函数有多个defer,只有退出作用域那行代码之前的defer才起作用,并且执行顺序是倒序。

e.g.

func vend(itemName itemName: String, money: Int) throws -> Int{
    
    defer{
        print("Have a nice day")
    }
    
    guard let item = items[itemName] else{
        throw VendingMachine.ItemError.NoSuchItem
    }
    
    guard money >= item.price else{
        throw VendingMachine.ItemError.NotEnoughMoney(item.price)
    }
    
    guard item.count > 0 else{
        throw VendingMachine.ItemError.OutOfStock
    }
    
    defer{ // 如果抛出异常了,这句话不会执行
        print("Thank you")
    }
    
    dispenseItem(itemName: itemName)
    
    return money - item.price
}

 

猜你喜欢

转载自blog.csdn.net/shijie97/article/details/84495404
今日推荐