Avoid stack overflow when rendering text with many attributed runs#57
Closed
larsjtx wants to merge 1 commit into
Closed
Avoid stack overflow when rendering text with many attributed runs#57larsjtx wants to merge 1 commit into
larsjtx wants to merge 1 commit into
Conversation
The reduce in TextBuilder built the result via Text("\(partialResult)\(text)"),
wrapping every attributed run in a LocalizedStringKey-backed Text.
At render time, SwiftUI's LocalizedStringKey.resolve walks the chain
and recurses ~8 stack frames per nesting level, overflowing the
main-thread stack for content that produces a few hundred runs
(e.g. emoji-dense notes where each emoji forms its own run).
Switch to Text + Text concatenation, which produces concat storage
that resolves linearly.
Fixes gonzalezreal#56
Owner
|
Sorry for the very late follow-up, and thank you for the fix! I merged #65, which fixes the same I really appreciate you digging into this. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TextBuilderreduced the per-runTextvalues viaText("\(partialResult)\(text)"), wrapping every run in aLocalizedStringKey-backedText. SwiftUI'sLocalizedStringKey.resolvewalks that chain at render time and recurses ~8 stack frames per nesting level, overflowing the main-thread stack for content that produces a few hundred runs (emoji-dense notes are an easy trigger — each emoji becomes its own run). Switching toText + Textproduces concat storage that resolves linearly.No regression test included: the crash only manifests inside SwiftUI's render pass on the main thread, which
swift testdoesn't exercise; a "construct 500-runTextand don't crash" test would either pass trivially (no render) or take the test runner down with it (if regressed). Happy to add one if you have a pattern in mind.Fixes #56