Skip to content

Commit

Permalink
fix: app acrash from "Mouting block is expected to not be set"
Browse files Browse the repository at this point in the history
  • Loading branch information
ezenwankwogabriel committed Dec 11, 2024
1 parent 2c63632 commit 29ede32
Showing 1 changed file with 66 additions and 33 deletions.
99 changes: 66 additions & 33 deletions ios/REANodesManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,71 @@ - (void)runSyncUIUpdatesWithObserver:(id<RCTUIManagerObserver>)observer

@end

@interface REANodesManager () <RCTUIManagerObserver>
#ifndef RCT_NEW_ARCH_ENABLED

@interface REASyncUpdateObserver : NSObject <RCTUIManagerObserver>
@end

@implementation REASyncUpdateObserver {
volatile void (^_mounting)(void);
volatile BOOL _waitTimedOut;
dispatch_semaphore_t _semaphore;
}

- (instancetype)init
{
self = [super init];
if (self) {
_mounting = nil;
_waitTimedOut = NO;
_semaphore = dispatch_semaphore_create(0);
}
return self;
}

- (void)dealloc
{
RCTAssert(_mounting == nil, @"Mouting block was set but never executed. This may lead to UI inconsistencies");
}

- (void)unblockUIThread
{
RCTAssertUIManagerQueue();
dispatch_semaphore_signal(_semaphore);
}

- (void)waitAndMountWithTimeout:(NSTimeInterval)timeout
{
RCTAssertMainQueue();
long result = dispatch_semaphore_wait(_semaphore, dispatch_time(DISPATCH_TIME_NOW, timeout * NSEC_PER_SEC));
if (result != 0) {
@synchronized(self) {
_waitTimedOut = YES;
}
}
if (_mounting) {
_mounting();
_mounting = nil;
}
}

- (BOOL)uiManager:(RCTUIManager *)manager performMountingWithBlock:(RCTUIManagerMountingBlock)block
{
RCTAssertUIManagerQueue();
@synchronized(self) {
if (_waitTimedOut) {
return NO;
} else {
_mounting = block;
return YES;
}
}
}

@end

#endif

@implementation REANodesManager {
NSMutableDictionary<REANodeID, REANode *> *_nodes;
NSMapTable<NSString *, REANode *> *_eventMapping;
Expand All @@ -108,9 +169,6 @@ @implementation REANodesManager {
NSMutableArray<REANativeAnimationOp> *_operationsInBatch;
BOOL _tryRunBatchUpdatesSynchronously;
REAEventHandler _eventHandler;
volatile void (^_mounting)(void);
NSObject *_syncLayoutUpdatesWaitLock;
volatile BOOL _syncLayoutUpdatesWaitTimedOut;
NSMutableDictionary<NSNumber *, ComponentUpdate *> *_componentUpdateBuffer;
volatile atomic_bool _shouldFlushUpdateBuffer;
NSMutableDictionary<NSNumber *, UIView *> *_viewRegistry;
Expand All @@ -130,7 +188,6 @@ - (instancetype)initWithModule:(REAModule *)reanimatedModule uiManager:(RCTUIMan
_operationsInBatch = [NSMutableArray new];
_componentUpdateBuffer = [NSMutableDictionary new];
_viewRegistry = [_uiManager valueForKey:@"_viewRegistry"];
_syncLayoutUpdatesWaitLock = [NSObject new];
_shouldFlushUpdateBuffer = false;
}

Expand Down Expand Up @@ -232,19 +289,6 @@ - (void)onAnimationFrame:(CADisplayLink *)displayLink
}
}

- (BOOL)uiManager:(RCTUIManager *)manager performMountingWithBlock:(RCTUIManagerMountingBlock)block
{
RCTAssert(_mounting == nil, @"Mouting block is expected to not be set");
@synchronized(_syncLayoutUpdatesWaitLock) {
if (_syncLayoutUpdatesWaitTimedOut) {
return NO;
} else {
_mounting = block;
return YES;
}
}
}

- (void)performOperations
{
if (_wantRunUpdates) {
Expand All @@ -258,8 +302,7 @@ - (void)performOperations
_tryRunBatchUpdatesSynchronously = NO;

__weak typeof(self) weakSelf = self;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
_syncLayoutUpdatesWaitTimedOut = NO;
REASyncUpdateObserver *syncUpdateObserver = [REASyncUpdateObserver new];
RCTExecuteOnUIManagerQueue(^{
__typeof__(self) strongSelf = weakSelf;
if (strongSelf == nil) {
Expand All @@ -268,7 +311,7 @@ - (void)performOperations
BOOL canUpdateSynchronously = trySynchronously && ![strongSelf.uiManager hasEnqueuedUICommands];

if (!canUpdateSynchronously) {
dispatch_semaphore_signal(semaphore);
[syncUpdateObserver unblockUIThread];
}

for (int i = 0; i < copiedOperationsQueue.count; i++) {
Expand All @@ -277,7 +320,7 @@ - (void)performOperations

if (canUpdateSynchronously) {
[strongSelf.uiManager runSyncUIUpdatesWithObserver:strongSelf];
dispatch_semaphore_signal(semaphore);
[syncUpdateObserver unblockUIThread];
}
// In case canUpdateSynchronously=true we still have to send uiManagerWillPerformMounting event
// to observers because some components (e.g. TextInput) update their UIViews only on that event.
Expand All @@ -288,17 +331,7 @@ - (void)performOperations
// from CADisplayLink but it is easier to hardcode it for the time being.
// The reason why we use frame duration here is that if takes longer than one frame to complete layout tasks
// there is no point of synchronizing layout with the UI interaction as we get that one frame delay anyways.
long result = dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 16 * NSEC_PER_MSEC));
if (result != 0) {
@synchronized(_syncLayoutUpdatesWaitLock) {
_syncLayoutUpdatesWaitTimedOut = YES;
}
}
}

if (_mounting) {
_mounting();
_mounting = nil;
[syncUpdateObserver waitAndMountWithTimeout:0.016];
}
}
_wantRunUpdates = NO;
Expand Down

0 comments on commit 29ede32

Please sign in to comment.