【问题标题】:Exception is not being caught异常没有被捕获
【发布时间】:2019-06-27 20:02:42
【问题描述】:

Crashlytics 报告以下行有时会抛出NSInternalInconsistencyException

let attrStr = try NSMutableAttributedString(
        data: modifiedFont.data(using: String.Encoding.unicode, 
        allowLossyConversion: true)!,
        options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue],
        documentAttributes: nil)

在这里,我对为什么会发生这种情况 (there's a 3 year old question about it) 不感兴趣,因为我对捕获/处理此异常不感兴趣。我试过这样做:

do {
    let attrStr = try NSMutableAttributedString(
       data: modifiedFont.data(using: String.Encoding.unicode, allowLossyConversion: true)!,
       options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue],
       documentAttributes: nil)

     self.attributedText = attrStr
} catch {
    self.attributedText = nil
    self.text = text.stripHTML()
}

...但这由于某种原因不起作用 - 仍在报告异常。

我是否试图以正确的方式捕捉它?能抓到吗?如果没有,我有什么选择?

【问题讨论】:

标签: ios swift nsattributedstring nsmutableattributedstring


【解决方案1】:

Swift 将具有可空返回和尾随 NSError** 参数的 Objective-C 方法转换为在 Swift 中抛出的方法。但是,在 Objective-C 中,您也可以抛出异常。这些与NSErrors 不同,Swift 没有捕捉到它们。事实上,在 Swift 中没有办法捕捉它们。您必须编写一个 Objective-C 包装器来捕获异常并以 Swift 可以处理的某种方式将其传回。

您可以在 Apple 文档 Handling Cocoa Errors in SwiftHandle Exceptions in Objective-C Only 部分中找到此内容。

所以事实证明你可以抓住它,但值得考虑是否应该(参见下面@Sulthan 的 cmets)。据我所知,大多数 Apple 框架都不是异常安全的(请参阅:Exceptions and the Cocoa Frameworks),因此您不能只捕获异常并继续执行,就好像什么都没发生一样。您最好的选择是尽可能保存并尽快退出。另一个需要考虑的问题是,除非您重新抛出异常,否则 Crashlytics 等框架不会将其报告给您。因此,如果您确实决定捕获它,您应该记录它和/或重新抛出它,以便您知道它正在发生。

【讨论】:

  • 总而言之,不建议捕获 Objective-C 异常,因为它们的传播通常会使对象处于无效状态,并且您无法从它们中成功恢复。
  • 是的,但您可以尽最大努力优雅地退出(例如,尽可能保存任何用户数据,记录任何可能有用的数据。)
  • 是的,可能有机会,但我认为这不是 OP 现在想要做的。
  • @Sulthan 说得好。我会用更多信息更新答案。
【解决方案2】:

NSInternalInconsistencyException 是一个不能被 Swift 代码捕获的 Objective-C 异常。您只能使用 Objective-C 代码捕获此类异常,因此您需要创建一个 Objective-C 包装器以从 Swift 代码中捕获此异常,例如使用以下 Objective-C 方法:

+ (NSException *)tryCatchWithBlock:(void (^)(void))block {
    @try {
        block();
    } @catch (NSException *exception) {
        return exception;
    } @catch (id exception) {
        return [NSException exceptionWithName:NSGenericException reason:nil userInfo:nil];
    }
    return nil;
}

这个方法是我的库的一部分,称为 LSCategories:https://github.com/leszek-s/LSCategories,带有各种有用的类别/扩展,因此您还可以轻松地将这个库与 CocoaPods 集成到您的 Swift 项目中,然后您可以通过像这样包装您的 swift 代码来捕获 NSInternalInconsistencyException :

let objcException = NSException.lsTryCatch {
    // put your swift code here
}

所以如果你想这样做,你可以如何捕获这个异常。但更重要的是,您应该调查为什么会在您的案例中发生此异常。也许您正在后台线程上调用您的代码。

【讨论】:

  • 您能指出具体的方法声明而不是大型实用程序回购吗?或者更好,你能复制这里的方法实现吗?否则,这不能很好地作为答案,而更像是一种自我推销。
  • 附带说明,如果您不设置时区,lsDateWithStringWithISO8601 将无法正常工作,请注意大多数校验和函数(crc32、adler)在 zlib 中可用。
  • 感谢有关 ISO8601 的说明,是的,我知道这些校验和在 zlib 中也可用。
【解决方案3】:

我猜当您尝试将modifiedFont 转换为Data 时会发生崩溃。
modifiedFont.data(using: String.Encoding.unicode, allowLossyConversion: true)! 如果将数据转换行移出 try-catch 范围,很可能会遇到同样的错误。为避免崩溃,请勿使用 force unwrap(!)。

如果在初始化 NSMutableAttributedString 期间抛出任何错误,则会被捕获。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-04
    • 2013-08-08
    • 2019-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多