NSError
桥接是 Swift 编译器中一个有趣的野兽。一方面,NSError
来自 Foundation 框架,您的应用程序可能会或可能不会使用它;另一方面,实际的桥接机制需要在编译器中执行,正确地,编译器应该对标准库之上的“高级”库有尽可能少的了解。
因此,编译器对什么知之甚少NSError
实际上是,相反,Error暴露三个属性 https://github.com/apple/swift/blob/master/stdlib/public/core/ErrorType.swift#L113它提供了完整的底层表示NSError
:
public protocol Error {
var _domain: String { get }
var _code: Int { get }
// Note: _userInfo is always an NSDictionary, but we cannot use that type here
// because the standard library cannot depend on Foundation. However, the
// underscore implies that we control all implementations of this requirement.
var _userInfo: AnyObject? { get }
// ...
}
NSError
,那么,有一个Swift 扩展符合Error并实现这三个属性 https://github.com/apple/swift/blob/master/stdlib/public/SDK/Foundation/NSError.swift#L302:
extension NSError : Error {
@nonobjc
public var _domain: String { return domain }
@nonobjc
public var _code: Int { return code }
@nonobjc
public var _userInfo: AnyObject? { return userInfo as NSDictionary }
// ...
}
有了这个,当你import Foundation
, any Error
可以转换为NSError
反之亦然,因为两者都暴露_domain
, _code
, and _userInfo
(这是编译器实际用来执行桥接的)。
The CustomNSError
协议通过允许您提供一个来发挥作用errorDomain
, errorCode
, and errorUserInfo
,然后通过各种扩展 https://github.com/apple/swift/blob/master/stdlib/public/SDK/Foundation/NSError.swift#L171作为他们的下划线版本:
public extension Error where Self : CustomNSError {
/// Default implementation for customized NSErrors.
var _domain: String { return Self.errorDomain }
/// Default implementation for customized NSErrors.
var _code: Int { return self.errorCode }
// ...
}
那么,怎么样EncodingError
and DecodingError
不同的?好吧,由于它们都是在标准库中定义的(无论您是否使用 Foundation,它都会存在,并且不能依赖于 Foundation),因此它们通过以下方式挂接到系统中:提供实施_domain, _code, and _userInfo直接地 https://github.com/apple/swift/blob/master/stdlib/public/core/Codable.swift.gyb#L1255.
由于这两种类型都提供这些变量的直接下划线版本,因此它们不会调用非下划线版本来获取域、代码和用户信息 - 直接使用值(而不是依赖于var _domain: String { return Self.errorDomain }
).
因此,实际上,您无法覆盖该行为,因为EncodingError
and DecodingError
已经提供此信息。相反,如果您想提供不同的代码/域/用户信息字典,您将需要编写一个函数,该函数需要EncodingError
/DecodingError
并返回你自己的NSError
,或类似的。