为什么任何错误都无条件地转换为NSError?

Bil*_*ill 7 nserror swift

很多时候,我会Error从框架中收到一个Swift 对象,这真的是一个NSError.

为了访问它的信息(例如code),我需要将其转换为NSError:

(error as NSError).code == ....
Run Code Online (Sandbox Code Playgroud)

为什么这只是一个无条件的as?如果我设计我自己的符合的错误类Error,它不一定是一个NSError,那么这怎么可能是执行这个演员的正确方法?

类型系统中是否存在某种特殊情况?这是一个向下倾斜,表现得像一个向上倾斜.

Ole*_*ann 8

我相信Error可以转换为的能力NSError被硬编码到编译器中,而实际的桥接是在Swift运行时中实现的.

runtime/ErrorObject.mm,我发现这个评论:

// This implements the object representation of the standard Error
// type, which represents recoverable errors in the language. This
// implementation is designed to interoperate efficiently with Cocoa libraries
// by:
// - ...
// - allowing a native Swift error to lazily "become" an NSError when
//   passed into Cocoa, allowing for cheap Swift to Cocoa interop
Run Code Online (Sandbox Code Playgroud)

这个功能:

/// Take an Error box and turn it into a valid NSError instance.
id
swift::_swift_stdlib_bridgeErrorToNSError(SwiftError *errorObject) {
    ...

  // Otherwise, calculate the domain, code, and user info, and
  // initialize the NSError.
  auto value = SwiftError::getIndirectValue(&errorObject);
  auto type = errorObject->getType();
  auto witness = errorObject->getErrorConformance();

  NSString *domain = getErrorDomainNSString(value, type, witness);
  NSInteger code = getErrorCode(value, type, witness);
  NSDictionary *userInfo = getErrorUserInfoNSDictionary(value, type, witness);

  ...
}
Run Code Online (Sandbox Code Playgroud)

ErrorHandling.rst文件说,这对理由:

应当可以把符合任意夫特枚举ErrorNSError通过使用限定类型名称为域密钥,则枚举作为错误代码,并转动到有效载荷的用户数据.

(部分文件可能已过时.)

这是(我认为)的类型检查至少一部分人的信息Error可以转换为NSError编码(也有可能更多):

  // Check whether the type is an existential that contains
  // Error. If so, it's bridged to NSError.
  if (type->isExistentialWithError()) {
    if (auto nsErrorDecl = getNSErrorDecl()) {
      // The corresponding value type is Error.
      if (bridgedValueType)
        *bridgedValueType = getErrorDecl()->getDeclaredInterfaceType();

      return nsErrorDecl->getDeclaredInterfaceType();
    }
  }
Run Code Online (Sandbox Code Playgroud)


fun*_*ct7 4

这是一个很好的问题。

我以为我在某处看到了“错误类型可以桥接到 NSError”,但这一定是 Xcode 或一些在线教程。

幸运的是我从swift/NSError.swift找到了这个。

// NSError and CFError conform to the standard Error protocol. Compiler
// magic allows this to be done as a "toll-free" conversion when an NSError
// or CFError is used as an Error existential.
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 }

  /// The "embedded" NSError is itself.
  @nonobjc
  public func _getEmbeddedNSError() -> AnyObject? {
    return self
  }
}

extension CFError : Error {
  public var _domain: String {
    return CFErrorGetDomain(self) as String
  }

  public var _code: Int {
    return CFErrorGetCode(self)
  }

  public var _userInfo: AnyObject? {
    return CFErrorCopyUserInfo(self) as AnyObject
  }

  /// The "embedded" NSError is itself.
  public func _getEmbeddedNSError() -> AnyObject? {
    return self
  }
}
Run Code Online (Sandbox Code Playgroud)