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

时间:2018-07-30 22:05:17

标签: swift nserror

很多时候,我将从框架中收到一个Swift Error对象,它实际上是一个NSError

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

(error as NSError).code == ....

为什么这只是无条件的as?如果我设计自己的符合Error的错误类,则不一定是NSError,那么这怎么是执行此强制转换的正确方法呢?

类型系统中是否存在某种特殊情况?这是下流,其行为类似于上流。

3 个答案:

答案 0 :(得分:7)

我相信Error可转换为NSError的功能已硬编码到编译器中,并且实际的桥接是在Swift运行时中实现的。

https://www.ghandi.com.mx中,我发现了以下评论:

// 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

还有runtime/ErrorObject.mm

/// 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);

  ...
}

this function说出了基本原理:

  

通过使用合格的类型名称作为域键,枚举器作为错误代码并转换有效负载,应该有可能将符合Error的任意Swift枚举转换为NSError进入用户数据。

(文档的某些部分可能已过时。)

ErrorHandling.rst document(我认为)类型检查器中至少有一部分是对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();
    }
  }

答案 1 :(得分:2)

这是一个很好的问题。

我以为我在某个地方看到了“错误类型可以桥接到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
  }
}

答案 2 :(得分:-2)

HashSet hs = new HashSet();
hs.addAll(demoArrayList); // demoArrayList= name of arrayList from which u want 
to remove duplicates 

demoArrayList.clear();
demoArrayList.addAll(hs);