【问题标题】:How to correctly bridge Swift Errors with arguments to NSError如何正确地将 Swift 错误与 NSError 的参数联系起来
【发布时间】:2019-12-19 16:37:24
【问题描述】:

我已经阅读了 Swift Evolution post on the improved bridging 和其他一些在线资源,但仍然缺少一些东西。

鉴于此自定义 Error 枚举:

    public enum MyNetworkError: Error {
        case networkOffline
        case httpError(status: Int)
        case unknown
        case systemError(errno: Int)
    }

Objective-C 应用程序应该能够读取错误对象并以某种方式提取错误名称(networkOfflinehttpErrorunknownsystemError)和大小写参数(httpError.status 和 @987654329 @)。

将上述转换为NSError 的结果令人惊讶,我正在尝试了解如何改进:

    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

    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)

鉴于应用报告的错误代码,现在更难分辨实际的错误情况。

其次,我希望这样一种智能机制(特别是因为它是编译器生成的)也可以将 case 参数复制到 userInfo 字典中 - 但它没有。

我做错了吗,还是我必须完全实现CustomNSError 协议才能获得有意义且一致的NSError 对象?当然,这是一个选项,但我希望它会自动完成(有点像 Codable 的魔法)。

另外,应用程序能否获取错误案例名称为String

作为参考,上面的 sn-ps 是在 Xcode 10.3 Playground 中执行的。

【问题讨论】:

    标签: ios swift cocoa nserror


    【解决方案1】:

    简答:对于基于整数的枚举错误类型,错误值按预期映射到NSError 代码。对于所有其他错误类型(例如具有关联值的枚举),您必须实现 CustomNSError 协议才能控制 NSError 代码和用户信息。

    一些细节:仅对于基于整数的错误类型,代码会从 Swift 桥接到NSError,例如:

    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。示例:

    struct StringError: Error {}
    
    let serr = StringError() as  NSError
    print(serr.code) // 1
    

    Type Layout 文档中描述了枚举“标签”。对于具有关联值的枚举,这不一定遵循声明案例的顺序。这就是您观察到“意外”NSError 代码的原因。

    因此正确的方法来实现CustomNSError协议,编译器不会为你合成这个。

    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]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多