【问题标题】:How can I throw an NSError from a Swift class and catch it in an Objective-C class?如何从 Swift 类中抛出 NSError 并在 Objective-C 类中捕获它?
【发布时间】:2020-02-15 17:56:51
【问题描述】:

我需要在 Objective-C 中实现一个 try-catch 结构来处理 Swift 抛出的 NSErrors。

我已经用 Swift 代码编写了一个 NetService 管理器,并且我正在一个已经存在的 Objective-C UI 上实现它。

但是,每当我从 Swift 类中抛出错误时,try-catch 结构都无法捕获错误并继续执行 finally 块。

Swift 错误定义:

enum NEONetServiceErrors: Int
{
    case requestMadeWithoutIp
}

struct NEONetServiceErrorStrings
{
    let requestMadeWithoutIp = ["NEONetService Error: Request made without IP": NEONetServiceErrors.requestMadeWithoutIp]
}

Swift 错误抛出:

@objc func requestHelloPage() throws
{
    if serviceiPAddress != nil
    {
        makeHelloRequest()
    }
    else
    {
        throw NSError(domain: errorStrings.domain, code: NEONetServiceErrors.requestMadeWithoutIp.rawValue, userInfo:errorStrings.requestMadeWithoutIp)
    }
}

Objective-C 属性:

@property NEONetServiceManager* netServiceManager;
@property NSError* _Nullable __autoreleasing * _Nullable netServiceError;

Objective-C 错误处理:

- (IBAction)pressUpdateButton:(id)sender
{
    @try
    {
        [self.netServiceManager requestHelloPageAndReturnError: self.netServiceError];
    }
    @catch (NSException *exception)
    {
        NSLog(@"Throwing");
    }
    @finally
    {
        NSLog(@"Finally");
    }
}

输出:

2019-10-18 14:47:03.289268-0300 NEOFirmUpdate[16533:2389800] Start
2019-10-18 14:47:03.292696-0300 NEOFirmUpdate[16533:2389800] Finally

你能帮我弄清楚我在错误处理方面做错了什么吗?

【问题讨论】:

    标签: ios objective-c swift error-handling cross-language


    【解决方案1】:

    在您的 Objective-C 代码中,您是 Catching 和 NSException,而不是 NSError

    Swift 自动在 Error 类型和 NSError 之间建立桥梁 班级。产生错误的 Objective-C 方法被导入为 Swift throw 的方法和 throw 的 Swift 方法被导入为 根据 Objective-C 产生错误的 Objective-C 方法 错误约定。

    更多信息您可以点击here

    【讨论】:

      【解决方案2】:

      问题在于 Swift 错误/Objective-C NSError 不是 NSException。您已配置为捕获 NSExceptions,但这无关紧要。

      当 Swift 抛出错误时,在 Objective-C 中“捕获”一个 NSError 的方法是使用 NSError** 参数间接进行,就像一直以来的做法一样。

      NSError* err = nil;
      BOOL ok = [self.netServiceManager requestHelloPageAndReturnError:&err];
      if (ok) {
          // proceed normally
      } else {
          // you got an error, it is sitting in `err`
      }
      

      (请注意 Swift 如何准确地提供 BOOL 结果,以便您可以实现正确的模式。)

      【讨论】:

      • 我对另一个答案的评论也适用于此处:Apple 文档表明您应该在尝试对 NSError 对象执行任何操作之前检查 返回值 是否成功或失败。
      • 是的@MartinR 我正要添加它。 OP 没有返回值,这是另一个问题。
      • 即自动翻译:@objc func requestHelloPage() throws 被导入到 Obj-C 为 - (BOOL)requestHelloPageAndReturnError:(NSError * *)error;
      【解决方案3】:

      那是因为您在那里使用了 Objective-C 异常,而不是实际检查错误。要检查 Objective-c 中的错误,您可以传递对指针的引用,如果出现问题,您的函数将填写该错误。

      NSError *serviceError = nil;
      [self.netServiceManager requestHelloPageAndReturnError:&serviceError];
      if (serviceError) {
          // there was a problem
      }
      

      如果这是一个异步调用,则需要在闭包中执行此操作:

      NSError *serviceError = nil;
      [self.netServiceManager requestHelloPage:^(NSError *error) {
          if (error) {
              // there was a problem
          }
      }];
      

      【讨论】:

      • 这并不完全正确。您总是首先检查返回值。如果那是NO(表示失败)那么你可以访问serviceError
      • 参考:developer.apple.com/library/archive/documentation/Cocoa/…:重要提示:成功或失败由方法的返回值指示。虽然间接返回 Cocoa 错误域中的错误对象的 Cocoa 方法如果通过直接返回 nil 或 NO 指示失败,则保证返回此类对象,但在尝试对NSError 对象。
      • 在哪些情况下您看到填写错误但操作成功?
      • 我没有“看到”它,因为我总是使用记录在案的错误检查模式:)
      猜你喜欢
      • 2016-02-18
      • 2010-11-15
      • 2018-12-22
      • 2011-08-27
      • 2015-11-05
      • 2020-10-28
      • 1970-01-01
      • 2017-01-09
      相关资源
      最近更新 更多