NSAttributedString 初始化抛出 NSRangeException

NSAttributedString initialization throws NSRangeException

我写了一个简单的扩展来解码 html 个实体:

extension String {
    func htmlDecode() -> String {
        if let encodedData = self.data(using: String.Encoding.unicode) {
            let attributedString = try! NSAttributedString(data: encodedData, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: String.Encoding.unicode], documentAttributes: nil)
            return attributedString.string
        }
        return self
    }
}

现在它在 if let attributedString …:

行抛出错误

*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 4 beyond bounds [0 .. 2]'

并且 self 不是 nil 之类的,只是像这样的 String

self = (String) "...über 25'000 Franken..."

这个奇怪的NSArray异常是从哪里来的?

似乎是一个错误,可能与 Swift 字符串处理字符的方式与 NSString 不同。

我会提交雷达。

我只是 运行 用另一个错误来解决这个错误:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_SwiftValue unsignedIntegerValue]: unrecognized selector sent to instance 0x60000024b790'

并且在这段代码中发现了一个严重的错误:

我正在将 String.Encoding.unicode - 一个 Swift 值 - 传递给一个 Objective-C 导致应用程序崩溃的方法。使用 String.Encoding.unicode.rawValue 后,崩溃消失了:

extension String {
    func htmlDecode() -> String {
        if let encodedData = self.data(using: String.Encoding.unicode) {
            if let attributedString = try? NSAttributedString(data: encodedData, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: String.Encoding.unicode.rawValue], documentAttributes: nil) {
                return attributedString.string
            }
        }
        return self
    }
}

瞎猜:你确定初始化发生在主线程上吗?

我遇到了完全相同的问题。我注意到在我的例子中,异常发生在可重现的条件下(UICollectionViewController 中的动画),但我无法找到真正的原因。我最好的猜测是它是一个框架错误,所以我也建议你提交雷达。

我最终将我的 HTML 格式化字符串在它工作时预渲染到缓存(又名数组)中,然后根据需要从中加载 NSAttributedStrings。

请注意,此解决方案可能不适合您的用例,因为我一次只需要处理有限数量的格式化字符串,因此知道提前呈现它们的费用。

在我的例子中,发生这种情况是因为我试图从处于分离状态的 UICollectionViewCell 中实例化一个 NSAttributedString(在它被插入父 UICollectionView 之前)。

DispatchQueue.main.async { let text = yourHtmlText.htmlDecode() }