首先,让我们看几个使用示例,然后是如何使这些示例起作用(定义)。
用法
do {
throw MyError.Failure
} catch {
print(error.localizedDescription)
}
或更具体的风格:
do {
try somethingThatThrows()
} catch MyError.Failure {
// Handle special case here.
} catch MyError.Rejected {
// Another special case...
} catch {
print(error.localizedDescription)
}
另外,分类是可能的:
do {
// ...
} catch is MyOtherErrorEnum {
// If you handle entire category equally.
} catch let error as MyError {
// Or handle few cases equally (without string-compare).
switch error {
case .Failure:
fallthrough;
case .Rejected:
myShowErrorDialog(error);
default:
break
}
}
定义
public enum MyError: String, LocalizedError {
case Failure = "Connection fail - double check internet access."
case Rejected = "Invalid credentials, try again."
case Unknown = "Unexpected REST-API error."
public var errorDescription: String? { self.rawValue }
}
优点和缺点
Swift 自动定义了error 变量,处理程序只需要读取localizedDescription 属性。
但这很模糊,我们应该使用“catch MyError.Failure {}”样式来代替(为了清楚我们处理什么情况),尽管分类是可能的,如用法示例所示。
-
Teodor-Ciuraru's answer(几乎相等)仍然需要长时间手动转换(如“catch let error as User.UserValidationError { ... }”)。
-
accepted categorization-enum approach's 的缺点:
- 是不是太含糊了,因为他是自己,所以捕手可能需要比较
String消息!? (只是为了知道确切的错误)。
- 要多次抛出相同的内容,需要复制/粘贴消息!!
- 此外,还需要一个长短语,例如“
catch MyError.runtimeError(let errorMessage) { ... }”。
-
NSException approach 具有与分类枚举方法相同的缺点(除了可能更短的捕获段落),而且即使放入工厂方法来创建和抛出,也相当复杂。
结论
这完善了其他现有的解决方案,只需使用LocalizedError 而不是Error,并希望避免有人像我一样阅读所有其他帖子。
(我的懒惰有时会给我带来很多工作。)
测试
import Foundation
import XCTest
@testable import MyApp
class MyErrorTest: XCTestCase {
func testErrorDescription_beSameAfterThrow() {
let obj = MyError.Rejected;
let msg = "Invalid credentials, try again."
XCTAssertEqual(obj.rawValue, msg);
XCTAssertEqual(obj.localizedDescription, msg);
do {
throw obj;
} catch {
XCTAssertEqual(error.localizedDescription, msg);
}
}
func testThrow_triggersCorrectCatch() {
// Specific.
var caught = "None"
do {
throw MyError.Rejected;
} catch MyError.Failure {
caught = "Failure"
} catch MyError.Rejected {
caught = "Successful reject"
} catch {
caught = "Default"
}
XCTAssertEqual(caught, "Successful reject");
}
}
其他工具:
#1如果为每个enum 实现errorDescription 很痛苦,那么就一劳永逸地实现它,例如:
extension RawRepresentable where RawValue == String, Self: LocalizedError {
public var errorDescription: String? {
return self.rawValue;
}
}
#2 如果我们需要额外的上下文,比如FileNotFound 关联文件路径怎么办?请参阅我的另一篇文章:
https://stackoverflow.com/a/70448052/8740349
基本上,将上述链接中的LocalizedErrorEnum 复制并添加到您的项目中一次,然后使用关联枚举根据需要重复使用多次。