Swift错误处理

1.错误的表示

Swift中用实现了Error协议的类型表示错误,通常用枚举来表示一组错误信息。

1
2
3
4
5
enum VendingMachineError: Error {
case invalidSelection
case insufficientFunds(coinsNeeded: Int)
case outOfStock
}

2.抛出错误

在方法的参数后,返回值前使用throws标记可能方法可能抛出错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
struct Item {
var price: Int
var count: Int
}

class VendingMachine {
var inventory = [
"Candy Bar": Item(price: 12, count: 7),
"Chips": Item(price: 10, count: 4),
"Pretzels": Item(price: 7, count: 11)
]
var coinsDeposited = 0

func vend(itemNamed name: String) throws { //抛出错误
guard let item = inventory[name] else {
throw VendingMachineError.invalidSelection
}

guard item.count > 0 else {
throw VendingMachineError.outOfStock
}

guard item.price <= coinsDeposited else {
throw VendingMachineError.insufficientFunds(coinsNeeded: item.price - coinsDeposited)
}

coinsDeposited -= item.price

var newItem = item
newItem.count -= 1
inventory[name] = newItem

print("Dispensing \(name)")
}
}

3.错误的处理

错误被抛出后,必须要有相应的代码块处理这个错误。可分四种处理方法:

  • 将错误传递给调用此函数的代码;
  • 使用do-catch语句处理错误;
  • 将错误作为可选类型处理;
  • 断言错误绝不会发生,万一真的发生则闪退;

错误会改变代码的执行路径,使用trytry?或者try!标记可能抛出错误的地方。

  • 示例1:传递错误
1
2
3
4
5
6
7
8
9
let favoriteSnacks = [
"Alice": "Chips",
"Bob": "Licorice",
"Eve": "Pretzels",
]
func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws { //向上传递错误
let snackName = favoriteSnacks[person] ?? "Candy Bar"
try vendingMachine.vend(itemNamed: snackName) //将错误向上传递
}
  • 示例2:do-catch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
do {
try expression
statements
} catch pattern 1 {
statements
} catch pattern 2 where condition {
statements
} catch pattern 3, pattern 4 where condition {
statements
} catch {
statements
}

//具体案例
var vendingMachine = VendingMachine()
vendingMachine.coinsDeposited = 8
do {
try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine)
print("Success! Yum.")
} catch VendingMachineError.invalidSelection {
print("Invalid Selection.")
} catch VendingMachineError.outOfStock {
print("Out of Stock.")
} catch VendingMachineError.insufficientFunds(let coinsNeeded) {
print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
} catch {
print("Unexpected error: \(error).")
}
// Prints "Insufficient funds. Please insert an additional 2 coins."
  • 示例3:try?转为可选类型
1
2
3
4
5
6
7
8
9
10
11
12
func someThrowingFunction() throws -> Int {
// ...
}

let x = try? someThrowingFunction()

let y: Int?
do {
y = try someThrowingFunction()
} catch {
y = nil
}

使用try?将可能抛出错误的方法的返回值转换成可选类型。如果未抛出错误,则try?表达式的值即为函数的值;如果抛出了错误则表达式的值为nil。

  • 示例4:try!
1
let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")

try!断言此方法的调用不会出现错误,如果真的抛出错误则会报运行时错误。

4.兼容NSError

Swift中Error可直接转换成OC中的NSError, 如SomeError.error0 as NSError,只是没有errorCode, domain等信息。如果想和NSError一样, 则需要实现LocalizedErrorCustomNSError协议:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
enum SwiftError: Error, LocalizedError, CustomNSError {
case error0, error1
public var errorDescription: String? {
switch self {
case .error0:
return "error description error0"
case .error1:
return "error description error1"
}
}
var errorCode: Int {
switch self {
case .error0:
return 0
case .error1:
return 1
}
}
public static var errorDomain: String {
return "error domain SwiftError"
}
public var errorUserInfo: [String : Any] {
switch self {
case .error0:
return ["info": "This is Error0"]
case .error1:
return ["info": "This is error1"]
}
}
}
print(SwiftError.error0 as NSError) //__lldb_expr_7.SwiftError.error0
print(SwiftError.error0.errorCode) //0

Swift错误处理
https://davidlii.cn/2018/08/25/swift-error.html
作者
Davidli
发布于
2018年8月25日
许可协议