You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

HTML转NSAttributedString时App崩溃(NSInternalInconsistencyException)

解决HTML转NSAttributedString时的NSInternalInconsistencyException崩溃

问题分析

从崩溃堆栈来看,异常出现在WebKit加载HTML内容时的内部字典初始化环节,属于系统框架偶发问题,通常和不完整的HTML结构、线程操作不当或临时对象内存管理异常有关。

解决方案

1. 给HTML字符串包裹完整的文档结构

不完整的HTML片段会导致解析器出现异常,给原始HTML包裹基础的<html><body>标签,确保解析器能正确识别文档结构:

extension String {
    var htmlToAttributedString: NSAttributedString? {
        // 包裹完整HTML结构
        let wrappedHTML = "<html><body>\(self)</body></html>"
        guard let data = wrappedHTML.data(using: .utf8) else { return NSAttributedString() }
        do {
            return try NSAttributedString(data: data, 
                                         options: [.documentType: NSAttributedString.DocumentType.html,
                                                   .characterEncoding: String.Encoding.utf8.rawValue],
                                         documentAttributes: nil)
        } catch {
            debugPrint("HTML转换失败: \(error)")
            return NSAttributedString(string: self) // 兜底返回原始字符串
        }
    }
}

2. 强制在主线程执行UI赋值操作

即使cellForRowAt默认在主线程,异步数据更新场景下仍可能出现线程错位,强制在主线程处理UITextView的属性赋值:

// 在cell的configure方法中
DispatchQueue.main.async {
    self.standingBillerNoteTextView.attributedText = isFlexSip ? 
        paymentVM.flexSipPaymentNotes.htmlToAttributedString : 
        paymentVM.sipSINotes.htmlToAttributedString ?? NSAttributedString()
}

3. 用AutoreleasePool包裹转换逻辑

HTML解析过程会创建大量临时对象,添加自动释放池可以避免内存相关的偶发异常:

extension String {
    var htmlToAttributedString: NSAttributedString? {
        let wrappedHTML = "<html><body>\(self)</body></html>"
        guard let data = wrappedHTML.data(using: .utf8) else { return NSAttributedString() }
        
        return autoreleasepool {
            do {
                return try NSAttributedString(data: data, 
                                             options: [.documentType: NSAttributedString.DocumentType.html,
                                                       .characterEncoding: String.Encoding.utf8.rawValue],
                                             documentAttributes: nil)
            } catch {
                debugPrint("HTML转换失败: \(error)")
                return NSAttributedString(string: self)
            }
        }
    }
}

4. 提前过滤空字符串与特殊字符

对空字符串或含特殊转义字符的HTML提前处理,避免解析器触发异常:

extension String {
    var htmlToAttributedString: NSAttributedString? {
        // 过滤空字符串
        let trimmedHTML = self.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !trimmedHTML.isEmpty else {
            return NSAttributedString()
        }
        // 转义特殊HTML字符
        let escapedHTML = trimmedHTML.replacingOccurrences(of: "&", with: "&amp;")
                              .replacingOccurrences(of: "<", with: "&lt;")
                              .replacingOccurrences(of: ">", with: "&gt;")
        let wrappedHTML = "<html><body>\(escapedHTML)</body></html>"
        
        guard let data = wrappedHTML.data(using: .utf8) else { return NSAttributedString() }
        
        return autoreleasepool {
            do {
                return try NSAttributedString(data: data, 
                                             options: [.documentType: NSAttributedString.DocumentType.html,
                                                       .characterEncoding: String.Encoding.utf8.rawValue],
                                             documentAttributes: nil)
            } catch {
                debugPrint("HTML转换失败: \(error)")
                return NSAttributedString(string: self)
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Gaurav Bisht

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 18:03:14