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

HTML字符串转AttributedString出现内存泄漏,求替代方案

HTML转AttributedString内存泄漏的替代解决方案

针对你遇到的系统HTML解析API内存泄漏问题,这里提供几个可行的替代方案:

方案一:优化原实现,复用解析配置

将解析用的options字典改为静态常量,避免每次调用时重复创建,减少内存分配风险:

extension String {
    // 全局复用的解析配置,仅初始化一次
    private static let htmlParseOptions: [NSAttributedString.DocumentReadingOptionKey: Any] = [
        .documentType: NSAttributedString.DocumentType.html
    ]
    
    var html2AttributedString: NSMutableAttributedString? {
        autoreleasepool {
            guard let htmlData = self.data(using: .utf16) else { return nil }
            do {
                return try NSMutableAttributedString(
                    data: htmlData,
                    options: Self.htmlParseOptions,
                    documentAttributes: nil
                )
            } catch {
                print("HTML解析失败: \(error)")
                return nil
            }
        }
    }
}

方案二:用第三方库手动构建富文本

如果系统API的泄漏问题无法解决,可以用轻量HTML解析库SwiftSoup手动解析标签并构建AttributedString,完全控制内存分配:

import SwiftSoup

extension String {
    var html2AttributedString: NSMutableAttributedString? {
        autoreleasepool {
            do {
                let doc = try SwiftSoup.parse(self)
                let resultString = NSMutableAttributedString()
                
                // 遍历HTML节点,根据标签设置对应样式
                for element in doc.body()?.children() ?? [] {
                    let text = try element.text()
                    var attributes = [NSAttributedString.Key: Any]()
                    
                    switch element.tagName().lowercased() {
                    case "h1":
                        attributes[.font] = UIFont.boldSystemFont(ofSize: 24)
                    case "h2":
                        attributes[.font] = UIFont.boldSystemFont(ofSize: 20)
                    case "b", "strong":
                        attributes[.font] = UIFont.boldSystemFont(ofSize: UIFont.systemFontSize)
                    default:
                        break
                    }
                    
                    resultString.append(NSAttributedString(string: text, attributes: attributes))
                }
                return resultString
            } catch {
                print("HTML解析失败: \(error)")
                return nil
            }
        }
    }
}

注:可根据需求扩展更多标签(如p、i等)的样式处理逻辑。

方案三:通过WKWebView间接处理复杂HTML

如果HTML包含复杂样式表或嵌套结构,可借助WKWebView加载后再提取富文本:

import WebKit

extension String {
    func html2AttributedString(completion: @escaping (NSMutableAttributedString?) -> Void) {
        let webView = WKWebView(frame: .zero)
        webView.loadHTMLString(self, baseURL: nil)
        
        webView.evaluateJavaScript("document.body.innerHTML") { result, error in
            guard let htmlContent = result as? String, error == nil else {
                completion(nil)
                return
            }
            
            guard let data = htmlContent.data(using: .utf16) else {
                completion(nil)
                return
            }
            
            let options: [NSAttributedString.DocumentReadingOptionKey: Any] = [
                .documentType: NSAttributedString.DocumentType.html
            ]
            
            do {
                let attrString = try NSMutableAttributedString(
                    data: data,
                    options: options,
                    documentAttributes: nil
                )
                completion(attrString)
            } catch {
                completion(nil)
            }
            
            // 及时释放webView避免内存占用
            webView.removeFromSuperview()
        }
    }
}

使用示例:

"<H1>Hello world</H1><h2><b>, abc</b><h2>".html2AttributedString { attrText in
    DispatchQueue.main.async {
        self.lblHeader.attributedText = attrText
    }
}

内容的提问来源于stack exchange,提问作者S K

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 00:25:19