History

Fix: suppress didSet observer during incremental token merge

In mergeTokensByRowId, each tokensByRowId[rowId] = tokens assignment triggered the didSet observer (Swift Dictionary is a value type), causing tokenAttributedStringsByRowId.removeAll(), clampHorizontalOffsets(), and setNeedsDisplayForVisibleBounds() to fire N times — once per patched row. This defeated the incremental cache invalidation the method intended and multiplied layout work for large token patches. Add a _suppressTokensByRowIdDidSet flag so the didSet observer is skipped during the merge loop. The method already performs its own targeted cache invalidation (removeValue per row) and calls clampHorizontalOffsets() and setNeedsDisplayForVisibleBounds() once at the end.

Cursor Agent committed 6 months ago

Commit e72d3641 parent 9b9fe0d1 file · +4 −0Browse files

Unified · Split

apps/mobile/modules/t3-review-diff/ios/T3ReviewDiffView.swift+4−0
@@ -689,8 +689,10 @@ private final class ReviewDiffContentView: UIView, UIGestureRecognizerDelegate { · 688 unmodified lines
689689 setNeedsDisplayForVisibleBounds()
690690 }
691691 }
692+ private var _suppressTokensByRowIdDidSet = false
692693 var tokensByRowId: [String: [ReviewDiffNativeToken]] = [:] {
693694 didSet {
695+ guard !_suppressTokensByRowIdDidSet else { return }
694696 tokenAttributedStringsByRowId.removeAll()
695697 clampHorizontalOffsets()
696698 setNeedsDisplayForVisibleBounds()
@@ -698,10 +700,12 @@ private final class ReviewDiffContentView: UIView, UIGestureRecognizerDelegate { · 1 unmodified line
698700 }
699701
700702 func mergeTokensByRowId(_ tokensPatch: [String: [ReviewDiffNativeToken]]) {
703+ _suppressTokensByRowIdDidSet = true
701704 tokensPatch.forEach { rowId, tokens in
702705 tokensByRowId[rowId] = tokens
703706 tokenAttributedStringsByRowId.removeValue(forKey: rowId)
704707 }
708+ _suppressTokensByRowIdDidSet = false
705709 clampHorizontalOffsets()
706710 setNeedsDisplayForVisibleBounds()
707711 }