如何正确地将带有参数的Swift错误桥接到NSError [英] How to correctly bridge Swift Errors with arguments to NSError
问题描述
我已经阅读了Swift Evolution 和其他一些在线资源发布在网上,但仍然缺少某些内容.
I've read the Swift Evolution post on the improved bridging and some other sources online, but still something is missing.
给出此自定义 Error
枚举:
public enum MyNetworkError: Error {
case networkOffline
case httpError(status: Int)
case unknown
case systemError(errno: Int)
}
Objective-C应用程序应该能够读取错误对象并以某种方式提取错误名称( networkOffline
, httpError
, unknown
, systemError
)和大小写参数( httpError.status
和 systemError.errno
).
An Objective-C app should be able to read the error object and somehow extract the error name (networkOffline
, httpError
, unknown
, systemError
) and the case arguments (httpError.status
and systemError.errno
).
将上述内容转换为 NSError
的结果令人惊讶,我正在尝试了解如何进行改进:
The result of converting the above to NSError
is surprising, and I'm trying to understand how to improve things:
let nse_A = MyNetworkError.networkOffline as NSError
let nse_B = MyNetworkError.httpError(status: 503) as NSError
let nse_C = MyNetworkError.unknown as NSError
let nse_D = MyNetworkError.systemError(42) as NSError
首先,生成错误代码.看来,带有参数的个案,无论其顺序如何,都从零开始获得 code
:
First, the generated error codes. It appears that the cases that have arguments, regardless of their order, get code
starting from zero:
print(nse_A.code) // 2 (expected: 0)
print(nse_B.code) // 0 (expected: 1)
print(nse_C.code) // 3 (expected: 2)
print(nse_D.code) // 1 (expected: 3)
给出应用程序报告的错误代码,现在更难分辨出实际的错误情况.
Given an error code reported by the app, now it's harder to tell the actual error case.
第二,我期望有这样一种聪明的机制(特别是因为它是由编译器生成的),还可以将大小写参数复制到 userInfo
词典中-但事实并非如此.
Second, I expected such a smart mechanism (especially since it's compiler-generated) to also copy the case arguments to the userInfo
dictionary - but it doesn't.
我做错了吗,还是必须完全实现 CustomNSError
协议才能获得有意义且一致的 NSError
对象?当然,这是一个选择,但我希望它可以自动完成(有点像 Codable
发挥其魔力的方式).
Am I doing it wrong, or do I have to fully implement the CustomNSError
protocol to get meaningful and consistent NSError
objects? That's an option, of course, but I expected it to be done automatically (kind of like how Codable
does its magic).
此外,应用程序能否以 String
的形式获取错误案例名称?
In addition, can the app get the error case name as a String
?
作为参考,以上代码片段是在Xcode 10.3 Playground中执行的.
For reference, the above snippets were executed in a Xcode 10.3 Playground.
推荐答案
简短答案:对于基于整数的枚举错误类型,错误值被映射为 NSError
代码,如下所示:预期的.对于所有其他错误类型(例如带有关联值的枚举),您必须实现 CustomNSError
协议,以便控制 NSError
代码和用户信息.
Short answer: For integer-based enum error types the error values are mapped to NSError
codes as expected. For all other error types (like enums with associated values) you have to implement the CustomNSError
protocol in order to control the NSError
code and user info.
一些详细信息:仅对于基于整数的错误类型,代码将从Swift桥接到 NSError
,例如:
Some details: Only for integer-based error types the code is bridged from Swift to NSError
, for example:
public enum IntNetworkError: Int, Error {
case networkOffline = 13
case httpError
case unknown
case systemError
}
let err = IntNetworkError.httpError as NSError
print(err.code) // 14
这是在中实现的特殊情况ErrorType.swift .对于所有其他错误类型,默认实现在 ErrorDefaultImpls.cpp ,对于枚举类型返回标签",对于所有其他类型返回 1
.示例:
That is a special case implemented in ErrorType.swift. For all other error types, the default implementation is in ErrorDefaultImpls.cpp, and that returns the "tag" for enum types, and 1
for all other types. Example:
struct StringError: Error {}
let serr = StringError() as NSError
print(serr.code) // 1
类型布局中描述了枚举标签"文档.对于具有关联值的枚举,这不一定遵循声明用例的顺序.这就是为什么您观察到意外"的 NSError
代码.
The enum "tag" is described in the Type Layout document. For enums with associated values, this does not necessarily follow the order in which the cases are declared. That is why you observed "unexpected" NSError
codes.
因此,正确的方法 是实现 CustomNSError
协议的方法,编译器不会为您综合此方法.
Therefore the correct approach is to implement the CustomNSError
protocol, the compiler does not synthesize this for you.
extension MyNetworkError: CustomNSError {
public static var errorDomain: String {
return "MyNetworkError"
}
public var errorCode: Int {
switch self {
case .networkOffline: return 1
case .httpError: return 2
case .unknown: return 3
case .systemError: return 4
}
}
public var errorUserInfo: [String : Any] {
switch self {
case .httpError(let status):
return [ "status": status]
case .systemError(let errno):
return [ "errno": errno]
default:
return [:]
}
}
}
let nse_B = MyNetworkError.httpError(status: 503) as NSError
print(nse_B.code) // 2
print(nse_B.userInfo) // ["status": 503]
这篇关于如何正确地将带有参数的Swift错误桥接到NSError的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!