如何正确地将带有参数的Swift错误桥接到NSError [英] How to correctly bridge Swift Errors with arguments to NSError

查看:72
本文介绍了如何正确地将带有参数的Swift错误桥接到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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆