Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions apple/LayoutReanimation/REASwizzledUIManager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#import <React/RCTRootShadowView.h>
#import <React/RCTRootViewInternal.h>
#import <React/RCTUIManager.h>
#import <React/RCTUIManagerUtils.h>
#import <objc/runtime.h>

@interface RCTUIManager (Reanimated)
@property REAAnimationsManager *animationsManager;
Expand All @@ -28,12 +30,22 @@ - (id)animationsManager

@implementation REASwizzledUIManager

std::atomic<uint> isFlushingBlocks;
std::atomic<bool> hasPendingBlocks;

- (instancetype)initWithUIManager:(RCTUIManager *)uiManager
withAnimationManager:(REAAnimationsManager *)animationsManager
{
if (self = [super init]) {
isFlushingBlocks = 0;
hasPendingBlocks = false;
[uiManager setAnimationsManager:animationsManager];
[self swizzleMethods];

IMP isExecutingUpdatesBatchImpl = imp_implementationWithBlock(^() {
return hasPendingBlocks || isFlushingBlocks > 0;
});
class_addMethod([RCTUIManager class], @selector(isExecutingUpdatesBatch), isExecutingUpdatesBatchImpl, "");
}
return self;
}
Expand All @@ -55,6 +67,18 @@ - (void)swizzleMethods
forClass:[RCTUIManager class]
with:manageChildrenReanimated
fromClass:[self class]];
[REAUtils swizzleMethod:@selector(addUIBlock:)
forClass:[RCTUIManager class]
with:@selector(reanimated_addUIBlock:)
fromClass:[self class]];
[REAUtils swizzleMethod:@selector(prependUIBlock:)
forClass:[RCTUIManager class]
with:@selector(reanimated_prependUIBlock:)
fromClass:[self class]];
[REAUtils swizzleMethod:@selector(flushUIBlocksWithCompletion:)
forClass:[RCTUIManager class]
with:@selector(reanimated_flushUIBlocksWithCompletion:)
fromClass:[self class]];
});
}

Expand Down Expand Up @@ -324,4 +348,32 @@ - (RCTViewManagerUIBlock)reanimated_uiBlockWithLayoutUpdateForRootView:(RCTRootS
};
}

- (void)reanimated_addUIBlock:(RCTViewManagerUIBlock)block
{
RCTAssertUIManagerQueue();
hasPendingBlocks = true;
[self reanimated_addUIBlock:block];
}

- (void)reanimated_prependUIBlock:(RCTViewManagerUIBlock)block
{
RCTAssertUIManagerQueue();
hasPendingBlocks = true;
[self reanimated_prependUIBlock:block];
}

- (void)reanimated_flushUIBlocksWithCompletion:(void (^)(void))completion
{
RCTAssertUIManagerQueue();
if (hasPendingBlocks) {
++isFlushingBlocks;
hasPendingBlocks = false;
[self reanimated_addUIBlock:^(
__unused RCTUIManager *manager, __unused NSDictionary<NSNumber *, REAUIView *> *viewRegistry) {
--isFlushingBlocks;
}];
}
[self reanimated_flushUIBlocksWithCompletion:completion];
}

@end
15 changes: 6 additions & 9 deletions apple/REANodesManager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ - (void)updateView:(nonnull NSNumber *)reactTag viewName:(NSString *)viewName pr

- (void)setNeedsLayout;

- (bool)isExecutingUpdatesBatch;

@end

@interface RCTUIManager (SyncUpdates)

- (BOOL)hasEnqueuedUICommands;

- (void)runSyncUIUpdatesWithObserver:(id<RCTUIManagerObserver>)observer;

@end
Expand All @@ -57,12 +57,6 @@ @implementation ComponentUpdate

@implementation RCTUIManager (SyncUpdates)

- (BOOL)hasEnqueuedUICommands
{
// Accessing some private bits of RCTUIManager to provide missing functionality
return [[self valueForKey:@"_pendingUIBlocks"] count] > 0;
}

- (void)runSyncUIUpdatesWithObserver:(id<RCTUIManagerObserver>)observer
{
// before we run uimanager batch complete, we override coordinator observers list
Expand Down Expand Up @@ -336,7 +330,10 @@ - (void)performOperations
if (strongSelf == nil) {
return;
}
BOOL canUpdateSynchronously = trySynchronously && ![strongSelf.uiManager hasEnqueuedUICommands];
// It is safe to call `isExecutingUpdatesBatch` in this context (Shadow thread) because both
// the Shadow thread and UI Thread are locked at this point. The UI Thread is specifically
// locked by the lock inside `REASyncUpdateObserver`, ensuring a safe reading operation.
BOOL canUpdateSynchronously = trySynchronously && ![strongSelf.uiManager isExecutingUpdatesBatch];

if (!canUpdateSynchronously) {
[syncUpdateObserver unblockUIThread];
Expand Down