Skip to content

Commit 80a52d3

Browse files
committed
refactor(ios): replace boolean flags with bitmask for segment rendering state management
1 parent ecc2bf0 commit 80a52d3

3 files changed

Lines changed: 32 additions & 41 deletions

File tree

ios/EnrichedMarkdown.mm

Lines changed: 28 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@
5353

5454
using namespace facebook::react;
5555

56+
typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
57+
ENRMDirtyNone = 0,
58+
ENRMDirtyRecreateSegments = 1 << 0,
59+
ENRMDirtyForceHeight = 1 << 1,
60+
};
61+
5662
static char kENRMSegmentFadeAnimatorKey;
5763

5864
@interface EnrichedMarkdown () <RCTEnrichedMarkdownViewProtocol, UITextViewDelegate>
@@ -67,8 +73,7 @@ @implementation EnrichedMarkdown {
6773
NSMutableArray<RCTUIView *> *_segmentViews;
6874
NSMutableArray<NSNumber *> *_segmentSignatures;
6975
ENRMSegmentViewRegistry *_segmentViewRegistry;
70-
BOOL _forceRecreateSegments;
71-
BOOL _forceHeightUpdateOnNextRender;
76+
ENRMDirtyFlags _dirtyFlags;
7277

7378
dispatch_queue_t _renderQueue;
7479
NSUInteger _currentRenderId;
@@ -107,8 +112,7 @@ - (instancetype)initWithFrame:(CGRect)frame
107112
_md4cFlags = [ENRMMd4cFlags defaultFlags];
108113
_segmentViews = [NSMutableArray array];
109114
_segmentSignatures = [NSMutableArray array];
110-
_forceRecreateSegments = NO;
111-
_forceHeightUpdateOnNextRender = NO;
115+
_dirtyFlags = ENRMDirtyNone;
112116
[self configureSegmentViewRegistry];
113117

114118
_renderQueue = dispatch_queue_create("com.swmansion.enriched.markdown.container.render", DISPATCH_QUEUE_SERIAL);
@@ -130,8 +134,7 @@ - (instancetype)initWithFrame:(CGRect)frame
130134
[strongSelf->_config setFontScaleMultiplier:strongSelf->_fontScaleObserver.effectiveFontScale];
131135
}
132136
if (strongSelf->_cachedMarkdown != nil && strongSelf->_cachedMarkdown.length > 0) {
133-
strongSelf->_forceRecreateSegments = YES;
134-
strongSelf->_forceHeightUpdateOnNextRender = YES;
137+
strongSelf->_dirtyFlags |= ENRMDirtyRecreateSegments | ENRMDirtyForceHeight;
135138
[strongSelf renderMarkdownContent:strongSelf->_cachedMarkdown];
136139
}
137140
};
@@ -148,17 +151,15 @@ - (void)configureSegmentViewRegistry
148151
matchesView:^BOOL(RCTUIView *view, ENRMRenderedSegment *segment) {
149152
return [view isKindOfClass:[EnrichedMarkdownInternalText class]];
150153
}
151-
createView:^RCTUIView *(ENRMRenderedSegment *segment, BOOL animateIfStreaming) {
154+
createView:^RCTUIView *(ENRMRenderedSegment *segment) {
152155
EnrichedMarkdown *strongSelf = weakSelf;
153156
if (!strongSelf) {
154157
return [[RCTUIView alloc] init];
155158
}
156159

157160
EnrichedMarkdownInternalText *view =
158161
[strongSelf createTextViewForRenderedSegment:segment.textResult];
159-
if (animateIfStreaming) {
160-
[strongSelf animateTextView:view fromTailStart:0];
161-
}
162+
[strongSelf animateTextView:view fromTailStart:0];
162163
return view;
163164
}
164165
updateView:^(RCTUIView *view, ENRMRenderedSegment *segment) {
@@ -173,16 +174,14 @@ - (void)configureSegmentViewRegistry
173174
matchesView:^BOOL(RCTUIView *view, ENRMRenderedSegment *segment) {
174175
return [view isKindOfClass:[TableContainerView class]];
175176
}
176-
createView:^RCTUIView *(ENRMRenderedSegment *segment, BOOL animateIfStreaming) {
177+
createView:^RCTUIView *(ENRMRenderedSegment *segment) {
177178
EnrichedMarkdown *strongSelf = weakSelf;
178179
if (!strongSelf) {
179180
return [[RCTUIView alloc] init];
180181
}
181182

182183
TableContainerView *view = [strongSelf createTableViewForSegment:segment.tableSegment];
183-
if (animateIfStreaming) {
184-
[strongSelf animateBlockViewIfNeeded:view];
185-
}
184+
[strongSelf animateBlockViewIfNeeded:view];
186185
return view;
187186
}
188187
updateView:^(RCTUIView *view, ENRMRenderedSegment *segment) {
@@ -194,17 +193,15 @@ - (void)configureSegmentViewRegistry
194193
matchesView:^BOOL(RCTUIView *view, ENRMRenderedSegment *segment) {
195194
return [view isKindOfClass:[ENRMMathContainerView class]];
196195
}
197-
createView:^RCTUIView *(ENRMRenderedSegment *segment, BOOL animateIfStreaming) {
196+
createView:^RCTUIView *(ENRMRenderedSegment *segment) {
198197
EnrichedMarkdown *strongSelf = weakSelf;
199198
if (!strongSelf) {
200199
return [[RCTUIView alloc] init];
201200
}
202201

203202
ENRMMathContainerView *view =
204203
[strongSelf createMathViewForSegment:(ENRMMathSegment *)segment.mathSegment];
205-
if (animateIfStreaming) {
206-
[strongSelf animateBlockViewIfNeeded:view];
207-
}
204+
[strongSelf animateBlockViewIfNeeded:view];
208205
return view;
209206
}
210207
updateView:^(RCTUIView *view, ENRMRenderedSegment *segment) {
@@ -421,7 +418,7 @@ - (void)renderMarkdownSynchronously:(NSString *)markdownString
421418
}
422419

423420
for (ENRMRenderedSegment *segment in renderedSegments) {
424-
RCTUIView *view = [_segmentViewRegistry createViewForSegment:segment animateIfStreaming:NO];
421+
RCTUIView *view = [_segmentViewRegistry createViewForSegment:segment];
425422
[_segmentViews addObject:view];
426423
[_segmentSignatures addObject:@(segment.signature)];
427424
[self addSubview:view];
@@ -436,9 +433,9 @@ - (void)applyRenderedSegments:(NSArray *)renderedSegments renderedMarkdown:(NSSt
436433
ENRMSegmentReconciliationResult *result = [ENRMSegmentReconciler reconcileCurrentViews:_segmentViews
437434
currentSignatures:_segmentSignatures
438435
renderedSegments:renderedSegments
439-
reset:_forceRecreateSegments
436+
reset:(_dirtyFlags & ENRMDirtyRecreateSegments) != 0
440437
createView:^RCTUIView *(ENRMRenderedSegment *segment) {
441-
return [self->_segmentViewRegistry createViewForSegment:segment animateIfStreaming:YES];
438+
return [self->_segmentViewRegistry createViewForSegment:segment];
442439
}
443440
updateView:^(RCTUIView *view, ENRMRenderedSegment *segment) {
444441
[self->_segmentViewRegistry updateView:view withSegment:segment];
@@ -448,16 +445,13 @@ - (void)applyRenderedSegments:(NSArray *)renderedSegments renderedMarkdown:(NSSt
448445
matchesKind:^BOOL(RCTUIView *view, ENRMRenderedSegment *segment) {
449446
return [self->_segmentViewRegistry view:view matchesSegment:segment];
450447
}];
451-
_forceRecreateSegments = NO;
448+
BOOL forceHeightUpdate = (_dirtyFlags & ENRMDirtyForceHeight) != 0;
449+
_dirtyFlags = ENRMDirtyNone;
452450

453451
_segmentViews = result.views;
454452
_segmentSignatures = result.signatures;
455453

456454
if (self.bounds.size.width > 0) {
457-
// Some prop changes recreate identical-looking segments but still change
458-
// Yoga height. Request one update instead of relying on size diffing.
459-
BOOL forceHeightUpdate = _forceHeightUpdateOnNextRender;
460-
_forceHeightUpdateOnNextRender = NO;
461455
[self setNeedsLayout];
462456

463457
if (forceHeightUpdate || segmentTopologyChanged) {
@@ -631,9 +625,9 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &
631625

632626
if (stylePropChanged) {
633627
[ENRMImageAttachment clearAttachmentRegistry];
634-
_forceHeightUpdateOnNextRender = YES;
628+
_dirtyFlags |= ENRMDirtyForceHeight;
635629
if (!markdownChanged) {
636-
_forceRecreateSegments = YES;
630+
_dirtyFlags |= ENRMDirtyRecreateSegments;
637631
}
638632
}
639633

@@ -654,8 +648,7 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &
654648
[_config setFontScaleMultiplier:_fontScaleObserver.effectiveFontScale];
655649
}
656650
stylePropChanged = YES;
657-
_forceRecreateSegments = YES;
658-
_forceHeightUpdateOnNextRender = YES;
651+
_dirtyFlags |= ENRMDirtyRecreateSegments | ENRMDirtyForceHeight;
659652
}
660653

661654
if (newViewProps.maxFontSizeMultiplier != oldViewProps.maxFontSizeMultiplier) {
@@ -664,26 +657,24 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &
664657
[_config setMaxFontSizeMultiplier:_maxFontSizeMultiplier];
665658
}
666659
stylePropChanged = YES;
667-
_forceRecreateSegments = YES;
668-
_forceHeightUpdateOnNextRender = YES;
660+
_dirtyFlags |= ENRMDirtyRecreateSegments | ENRMDirtyForceHeight;
669661
}
670662

671663
if (newViewProps.allowTrailingMargin != oldViewProps.allowTrailingMargin) {
672664
_allowTrailingMargin = newViewProps.allowTrailingMargin;
673-
_forceRecreateSegments = YES;
674-
_forceHeightUpdateOnNextRender = YES;
665+
_dirtyFlags |= ENRMDirtyRecreateSegments | ENRMDirtyForceHeight;
675666
}
676667

677668
BOOL md4cFlagsChanged = NO;
678669
if (newViewProps.md4cFlags.underline != oldViewProps.md4cFlags.underline) {
679670
_md4cFlags.underline = newViewProps.md4cFlags.underline;
680671
md4cFlagsChanged = YES;
681-
_forceHeightUpdateOnNextRender = YES;
672+
_dirtyFlags |= ENRMDirtyForceHeight;
682673
}
683674
if (newViewProps.md4cFlags.latexMath != oldViewProps.md4cFlags.latexMath) {
684675
_md4cFlags.latexMath = newViewProps.md4cFlags.latexMath;
685676
md4cFlagsChanged = YES;
686-
_forceHeightUpdateOnNextRender = YES;
677+
_dirtyFlags |= ENRMDirtyForceHeight;
687678
}
688679
BOOL allowTrailingMarginChanged = newViewProps.allowTrailingMargin != oldViewProps.allowTrailingMargin;
689680

@@ -692,7 +683,7 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &
692683
BOOL streamingAnimationChanged = newViewProps.streamingAnimation != oldViewProps.streamingAnimation;
693684
if (streamingAnimationChanged) {
694685
_streamingAnimation = newViewProps.streamingAnimation;
695-
_forceHeightUpdateOnNextRender = YES;
686+
_dirtyFlags |= ENRMDirtyForceHeight;
696687
if (!_streamingAnimation) {
697688
for (RCTUIView *segment in _segmentViews) {
698689
if ([segment isKindOfClass:[EnrichedMarkdownInternalText class]]) {

ios/utils/SegmentViewRegistry.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
NS_ASSUME_NONNULL_BEGIN
77

88
typedef BOOL (^ENRMSegmentMatchesViewBlock)(RCTUIView *view, ENRMRenderedSegment *segment);
9-
typedef RCTUIView *_Nonnull (^ENRMSegmentCreateViewBlock)(ENRMRenderedSegment *segment, BOOL animateIfStreaming);
9+
typedef RCTUIView *_Nonnull (^ENRMSegmentCreateViewBlock)(ENRMRenderedSegment *segment);
1010
typedef void (^ENRMSegmentUpdateViewBlock)(RCTUIView *view, ENRMRenderedSegment *segment);
1111

1212
@interface ENRMSegmentViewHandler : NSObject
@@ -28,7 +28,7 @@ typedef void (^ENRMSegmentUpdateViewBlock)(RCTUIView *view, ENRMRenderedSegment
2828
- (instancetype)initWithHandlers:(NSArray<ENRMSegmentViewHandler *> *)handlers;
2929

3030
- (BOOL)view:(RCTUIView *)view matchesSegment:(ENRMRenderedSegment *)segment;
31-
- (RCTUIView *)createViewForSegment:(ENRMRenderedSegment *)segment animateIfStreaming:(BOOL)animateIfStreaming;
31+
- (RCTUIView *)createViewForSegment:(ENRMRenderedSegment *)segment;
3232
- (void)updateView:(RCTUIView *)view withSegment:(ENRMRenderedSegment *)segment;
3333

3434
@end

ios/utils/SegmentViewRegistry.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,14 @@ - (BOOL)view:(RCTUIView *)view matchesSegment:(ENRMRenderedSegment *)segment
4545
return handler != nil && handler.matchesView(view, segment);
4646
}
4747

48-
- (RCTUIView *)createViewForSegment:(ENRMRenderedSegment *)segment animateIfStreaming:(BOOL)animateIfStreaming
48+
- (RCTUIView *)createViewForSegment:(ENRMRenderedSegment *)segment
4949
{
5050
ENRMSegmentViewHandler *handler = [self handlerForSegment:segment];
5151
NSAssert(handler != nil, @"Missing segment view handler for kind %ld", (long)segment.kind);
5252
if (!handler) {
5353
return [[RCTUIView alloc] init];
5454
}
55-
return handler.createView(segment, animateIfStreaming);
55+
return handler.createView(segment);
5656
}
5757

5858
- (void)updateView:(RCTUIView *)view withSegment:(ENRMRenderedSegment *)segment

0 commit comments

Comments
 (0)