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: "&") .replacingOccurrences(of: "<", with: "<") .replacingOccurrences(of: ">", with: ">") 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
相关产品推荐
相关产品推荐

