Skip to content

iOS: Synchronous per-cell UITextView TextKit layout blocks the main thread #417

Description

@lisabaut

Describe the bug
Synchronous per-cell UITextView TextKit layout blocks the main thread → multi-second iOS AppHangs for messages containing tables.

Summary — Rendering a markdown message with a table allocates and lays out one TextKit 1 UITextView per cell, synchronously on the main thread. Large tables block long enough to trip the iOS AppHang watchdog — app hangs of 10–19s routinely, up to ~85s, including fatal watchdog kills. iOS only, worse on iPad.

Environment — Library 0.6.0. React Native 0.85.3, React 19.2.3, Expo SDK 56, Fabric. (Production captures below were taken on RN 0.83 / Expo 55 builds; the 0.6.0 table-render path is unchanged, so it persists on the current stack.)

Mechanism — two synchronous sub-paths, both must be covered by a fix:

(a) Table render (18.6–19.4s hang):

  • [TableContainerView addTextToCell:data:width:height:]
  • [UITextView setFrame:] [NSTextLayoutManager ensureLayoutForBounds:] ← per cell

(b) Shadow-node measure (14.2–15.0s hang):

  • EnrichedMarkdownShadowNode::measureContentsetupMockEnrichedMarkdown_
    [EnrichedMarkdown renderMarkdownSynchronously:]
  • Cost = ensureLayoutForBounds: (full typesetting) per cell; scales with cell count × text length.

Already tried (doesn't fix this path) — upgraded to 0.6.0 (helped a separate dealloc storm, not this render); a plain-text fast path (can't cover tables).

Question — Per-cell synchronous TextKit typesetting blocks the main thread (up to ~85s on large tables). What approach would you recommend / accept a PR toward to keep large-table rendering off the synchronous main-thread layout path — a lighter non-UITextView cell renderer, virtualized/lazy layout, or batched typesetting?

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions