@@ -25,6 +25,21 @@ @implementation ENRMSegmentReconciler
2525 sourceSignatures = @[];
2626 }
2727
28+ // Build a signature -> (view, index) lookup for fallback reuse when
29+ // positional matching fails (e.g. a new segment inserted before an
30+ // existing table shifts it to a different index).
31+ NSMutableDictionary <NSNumber *, NSMutableArray <NSNumber *> *> *signatureToIndices =
32+ [NSMutableDictionary dictionaryWithCapacity: sourceSignatures.count];
33+ [sourceSignatures enumerateObjectsUsingBlock: ^(NSNumber *sig, NSUInteger idx, BOOL *stop) {
34+ NSMutableArray <NSNumber *> *indices = signatureToIndices[sig];
35+ if (!indices) {
36+ indices = [NSMutableArray arrayWithObject: @(idx)];
37+ signatureToIndices[sig] = indices;
38+ } else {
39+ [indices addObject: @(idx)];
40+ }
41+ }];
42+
2843 NSMutableArray <RCTUIView *> *nextViews = [NSMutableArray arrayWithCapacity: renderedSegments.count];
2944 NSMutableArray <NSNumber *> *nextSignatures = [NSMutableArray arrayWithCapacity: renderedSegments.count];
3045 NSMutableSet <RCTUIView *> *reusedViews = [NSMutableSet setWithCapacity: sourceViews.count];
@@ -35,12 +50,30 @@ @implementation ENRMSegmentReconciler
3550 RCTUIView *view = nil ;
3651 NSNumber *nextSignature = @(segment.signature );
3752
38- if (existingView && matchesKind (existingView, segment)) {
53+ // 1. Positional match: same index, same kind.
54+ if (existingView && ![reusedViews containsObject: existingView] && matchesKind (existingView, segment)) {
3955 if (![existingSignature isEqual: nextSignature]) {
4056 updateView (existingView, segment);
4157 }
4258 view = existingView;
43- } else {
59+ }
60+
61+ // 2. Signature-based fallback: find an unused view with exact same signature.
62+ if (!view) {
63+ NSMutableArray <NSNumber *> *candidateIndices = signatureToIndices[nextSignature];
64+ while (candidateIndices.count > 0 ) {
65+ NSUInteger candidateIdx = candidateIndices.firstObject .unsignedIntegerValue ;
66+ [candidateIndices removeObjectAtIndex: 0 ];
67+ RCTUIView *candidate = sourceViews[candidateIdx];
68+ if (![reusedViews containsObject: candidate] && matchesKind (candidate, segment)) {
69+ view = candidate;
70+ break ;
71+ }
72+ }
73+ }
74+
75+ // 3. No reusable view found — create a new one.
76+ if (!view) {
4477 view = createView (segment);
4578 attachView (view);
4679 }
0 commit comments