Skip to content

Commit 9465c1a

Browse files
Make sure blocks are added before the batch is flushed
1 parent 72e4865 commit 9465c1a

File tree

4 files changed

+52
-4
lines changed

4 files changed

+52
-4
lines changed

Libraries/NativeAnimation/RCTNativeAnimatedModule.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@
1010
#import <React/RCTBridgeModule.h>
1111
#import <React/RCTEventDispatcher.h>
1212
#import <React/RCTEventEmitter.h>
13+
#import <React/RCTUIManager.h>
1314

1415
#import "RCTValueAnimatedNode.h"
1516

16-
@interface RCTNativeAnimatedModule : RCTEventEmitter <RCTBridgeModule, RCTValueAnimatedNodeObserver, RCTEventDispatcherObserver>
17+
@interface RCTNativeAnimatedModule : RCTEventEmitter <RCTBridgeModule, RCTValueAnimatedNodeObserver, RCTEventDispatcherObserver, RCTUIManagerObserver>
1718

1819
@end

Libraries/NativeAnimation/RCTNativeAnimatedModule.m

+5-3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ - (void)invalidate
2828
{
2929
[_nodesManager stopAnimationLoop];
3030
[self.bridge.eventDispatcher removeDispatchObserver:self];
31+
[self.bridge.uiManager removeUIManagerObserver:self];
3132
}
3233

3334
- (dispatch_queue_t)methodQueue
@@ -44,6 +45,7 @@ - (void)setBridge:(RCTBridge *)bridge
4445
_preOperations = [NSMutableArray new];
4546

4647
[bridge.eventDispatcher addDispatchObserver:self];
48+
[bridge.uiManager addUIManagerObserver:self];
4749
}
4850

4951
#pragma mark -- API
@@ -191,7 +193,7 @@ - (void)addPreOperationBlock:(AnimatedOperation)operation
191193
[_preOperations addObject:operation];
192194
}
193195

194-
- (void)batchDidComplete
196+
- (void)uiManagerWillFlushUIBlocks:(RCTUIManager *)uiManager
195197
{
196198
if (_preOperations.count == 0 && _operations.count == 0) {
197199
return;
@@ -202,13 +204,13 @@ - (void)batchDidComplete
202204
_preOperations = [NSMutableArray new];
203205
_operations = [NSMutableArray new];
204206

205-
[self.bridge.uiManager prependUIBlock:^(__unused RCTUIManager *uiManager, __unused NSDictionary<NSNumber *, UIView *> *viewRegistry) {
207+
[uiManager prependUIBlock:^(__unused RCTUIManager *manager, __unused NSDictionary<NSNumber *, UIView *> *viewRegistry) {
206208
for (AnimatedOperation operation in preOperations) {
207209
operation(_nodesManager);
208210
}
209211
}];
210212

211-
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, __unused NSDictionary<NSNumber *, UIView *> *viewRegistry) {
213+
[uiManager addUIBlock:^(__unused RCTUIManager *manager, __unused NSDictionary<NSNumber *, UIView *> *viewRegistry) {
212214
for (AnimatedOperation operation in operations) {
213215
operation(_nodesManager);
214216
}

React/Modules/RCTUIManager.h

+25
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,20 @@ RCT_EXTERN NSString *const RCTUIManagerRootViewKey;
5050

5151
@class RCTUIManager;
5252

53+
/**
54+
* Allows to hook into UIManager internals. This can be used to execute code at
55+
* specific points during the view updating process.
56+
*/
57+
@protocol RCTUIManagerObserver <NSObject>
58+
59+
/**
60+
* Called before flushing UI blocks at the end of a batch. This is called from
61+
* the UIManager queue. Can be used to add UI operations in that batch.
62+
*/
63+
- (void)uiManagerWillFlushUIBlocks:(RCTUIManager *)manager;
64+
65+
@end
66+
5367
@protocol RCTScrollableProtocol;
5468

5569
/**
@@ -112,6 +126,17 @@ RCT_EXTERN NSString *const RCTUIManagerRootViewKey;
112126
*/
113127
- (void)prependUIBlock:(RCTViewManagerUIBlock)block;
114128

129+
/**
130+
* Add a UIManagerObserver. See the RCTUIManagerObserver protocol for more info. This
131+
* method can be called safely from any queue.
132+
*/
133+
- (void)addUIManagerObserver:(id<RCTUIManagerObserver>)observer;
134+
135+
/**
136+
* Remove a UIManagerObserver. This method can be called safely from any queue.
137+
*/
138+
- (void)removeUIManagerObserver:(id<RCTUIManagerObserver>)observer;
139+
115140
/**
116141
* Used by native animated module to bypass the process of updating the values through the shadow
117142
* view hierarchy. This method will directly update native views, which means that updates for

React/Modules/RCTUIManager.m

+20
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ @implementation RCTUIManager
224224
NSDictionary *_componentDataByName;
225225

226226
NSMutableSet<id<RCTComponent>> *_bridgeTransactionListeners;
227+
NSMutableSet<id<RCTUIManagerObserver>> *_uiManagerObservers;
227228
#if !TARGET_OS_TV
228229
UIInterfaceOrientation _currentInterfaceOrientation;
229230
#endif
@@ -326,6 +327,7 @@ - (void)setBridge:(RCTBridge *)bridge
326327
_rootViewTags = [NSMutableSet new];
327328

328329
_bridgeTransactionListeners = [NSMutableSet new];
330+
_uiManagerObservers = [NSMutableSet new];
329331

330332
_viewsToBeDeleted = [NSMutableSet new];
331333

@@ -736,6 +738,20 @@ - (void)_amendPendingUIBlocksWithStylePropagationUpdateForShadowView:(RCTShadowV
736738
}
737739
}
738740

741+
- (void)addUIManagerObserver:(id<RCTUIManagerObserver>)observer
742+
{
743+
dispatch_async(RCTGetUIManagerQueue(), ^{
744+
[_uiManagerObservers addObject:observer];
745+
});
746+
}
747+
748+
- (void)removeUIManagerObserver:(id<RCTUIManagerObserver>)observer
749+
{
750+
dispatch_async(RCTGetUIManagerQueue(), ^{
751+
[_uiManagerObservers removeObject:observer];
752+
});
753+
}
754+
739755
/**
740756
* A method to be called from JS, which takes a container ID and then releases
741757
* all subviews for that container upon receipt.
@@ -1177,6 +1193,10 @@ - (void)_layoutAndMount
11771193
}
11781194
}];
11791195

1196+
for (id<RCTUIManagerObserver> observer in _uiManagerObservers) {
1197+
[observer uiManagerWillFlushUIBlocks:self];
1198+
}
1199+
11801200
[self flushUIBlocks];
11811201
}
11821202

0 commit comments

Comments
 (0)