Skip to content

Commit

Permalink
New UIManager API allowing intercept/delay mounting process
Browse files Browse the repository at this point in the history
Summary: In some embedding/interop cases (RN inside, something else outside), the interop layer has to have the ability to control (intercept, delay, perform synchronously with another stuff) mounting process. This API allows doing that.

Reviewed By: fkgozali

Differential Revision: D7014179

fbshipit-source-id: 04036095f7e60a5ff7e69025ff6066fea92eb361
  • Loading branch information
shergin authored and facebook-github-bot committed Feb 21, 2018
1 parent 60c0000 commit 402ae2f
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 8 deletions.
31 changes: 23 additions & 8 deletions React/Modules/RCTUIManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -1081,21 +1081,36 @@ - (void)flushUIBlocksWithCompletion:(void (^)(void))completion;
return;
}

// Execute the previously queued UI blocks
RCTProfileBeginFlowEvent();
RCTExecuteOnMainQueue(^{
RCTProfileEndFlowEvent();
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[UIManager flushUIBlocks]", (@{
@"count": [@(previousPendingUIBlocks.count) stringValue],
}));
__weak typeof(self) weakSelf = self;

void (^mountingBlock)(void) = ^{
typeof(self) strongSelf = weakSelf;

@try {
for (RCTViewManagerUIBlock block in previousPendingUIBlocks) {
block(self, self->_viewRegistry);
block(strongSelf, strongSelf->_viewRegistry);
}
}
@catch (NSException *exception) {
RCTLogError(@"Exception thrown while executing UI block: %@", exception);
}
};

if ([self.observerCoordinator uiManager:self performMountingWithBlock:mountingBlock]) {
completion();
return;
}

// Execute the previously queued UI blocks
RCTProfileBeginFlowEvent();
RCTExecuteOnMainQueue(^{
RCTProfileEndFlowEvent();
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[UIManager flushUIBlocks]", (@{
@"count": [@(previousPendingUIBlocks.count) stringValue],
}));

mountingBlock();

RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");

RCTExecuteOnUIManagerQueue(completion);
Expand Down
9 changes: 9 additions & 0 deletions React/Modules/RCTUIManagerObserverCoordinator.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

#import <React/RCTViewManager.h>

typedef dispatch_block_t RCTUIManagerMountingBlock;

/**
* Allows hooking into UIManager internals. This can be used to execute code at
* specific points during the view updating process.
Expand Down Expand Up @@ -43,6 +45,13 @@
*/
- (void)uiManagerWillPerformMounting:(RCTUIManager *)manager;

/**
* Called right before flushing UI blocks and allows to intercept the mounting process.
* Return `YES` to cancel default execution of the `block` (and perform the
* execution later).
*/
- (BOOL)uiManager:(RCTUIManager *)manager performMountingWithBlock:(RCTUIManagerMountingBlock)block;

/**
* Called just after flushing UI blocks.
* This is called from the UIManager queue.
Expand Down
14 changes: 14 additions & 0 deletions React/Modules/RCTUIManagerObserverCoordinator.mm
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,20 @@ - (void)uiManagerWillPerformMounting:(RCTUIManager *)manager
}
}

- (BOOL)uiManager:(RCTUIManager *)manager performMountingWithBlock:(RCTUIManagerMountingBlock)block
{
std::lock_guard<std::mutex> lock(_mutex);

for (id<RCTUIManagerObserver> observer in _observers) {
if ([observer respondsToSelector:@selector(uiManager:performMountingWithBlock:)]) {
if ([observer uiManager:manager performMountingWithBlock:block]) {
return YES;
}
}
}
return NO;
}

- (void)uiManagerDidPerformMounting:(RCTUIManager *)manager
{
std::lock_guard<std::mutex> lock(_mutex);
Expand Down

0 comments on commit 402ae2f

Please sign in to comment.