记录于 2026-04-20。结论来自代码静态分析,尚未经 Instruments 验证。
PostNativeCell 配合 UITableView.automaticDimension(见 dexo/Features/ForumDetail/TopicDetail/PostNativeCell.swift:256-262 附近的高度配置)。tableView 滚动到一个长贴 cell 时,会同步触发 systemLayoutSizeFitting,需要 autolayout 求解整个 stack view + Core Text 全量排版,容易超 16.6ms 帧预算。
PostNativeCell.swift:565-592 的 Tier 3(完整渲染)路径在 configure 时重建 stack view 子视图、为每个 paragraph 构造 NSAttributedString、批量加载 inline emoji。长贴 20+ block 时,主线程被堵在配置上;TopicDetailViewModel.swift:380-384 也参与这条链路。
dexo/Features/ForumDetail/TopicDetail/NativeContent/ParagraphRenderer.swift:24-38 每渲染一段就 alloc 一个 LinkTextView。LinkTextView 设置 attributedText 触发 Core Text 初次排版,有 spoiler 时还要枚举 range 加模糊层。长贴反复 alloc 累积开销大。
跑 Instruments Time Profiler,录 2–3 秒快速滚动,看主线程采样里这三者占比:
systemLayoutSizeFitting/-[NSISEngine ...](autolayout)-[NSLayoutManager _layout...]/CTTypesetter...(Core Text)renderBlocks/configure自己的栈帧
辅助:System Trace 找持续 >25ms 的主线程阻塞;Allocations 看一次滚动里 UITextView/NSAttributedString 的分配次数。
文章核心是把 SwiftSoup 换成自写 tokenizer 跳过 DOM tree 构造,在 Mastodon 短文本流上拿到 ~2.7× 解析提速。对本项目滚动掉帧相关性低:
- 我们瓶颈不在 HTML→AST,在下游的 cell 配置(autolayout + Core Text + view alloc)。
- CookedHTML 需要识别 quote / onebox / table / 列表等 Discourse 结构,必须有树,token 流不够。换解析器风险大、收益小。
- 唯一沾边的思路是"把 NSAttributedString 构造搬到后台预渲染" — 但收益来自换线程,不是换解析器。
- 高度预缓存(根据
cookedHTML hash → cell 高度) - 后台预渲染
NSAttributedString,主线程只 set LinkTextView复用池,避免反复 alloc- 长贴按段懒加载或按屏幕外裁剪