Fabric: Polishing RCTSurfacePresenter
Summary: Now RCTSurfacePresenter is uniquely responsible for: * Starting and stopping JS apps; * Restarting JS apps during hot-reload; * Recreating Scheduler during hot-reload. Reviewed By: mdvacca Differential Revision: D9931318 fbshipit-source-id: a6a3fb58814222f71cc6cb2caad620ed6319089d
This commit is contained in:
Родитель
24ffd8f6fb
Коммит
bce94dc8c3
|
@ -37,6 +37,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
*/
|
*/
|
||||||
- (void)registerSurface:(RCTFabricSurface *)surface;
|
- (void)registerSurface:(RCTFabricSurface *)surface;
|
||||||
- (void)unregisterSurface:(RCTFabricSurface *)surface;
|
- (void)unregisterSurface:(RCTFabricSurface *)surface;
|
||||||
|
- (void)setProps:(NSDictionary *)props
|
||||||
|
surface:(RCTFabricSurface *)surface;
|
||||||
|
|
||||||
- (nullable RCTFabricSurface *)surfaceForRootTag:(ReactTag)rootTag;
|
- (nullable RCTFabricSurface *)surfaceForRootTag:(ReactTag)rootTag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,6 +60,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
@interface RCTSurfacePresenter (Deprecated)
|
@interface RCTSurfacePresenter (Deprecated)
|
||||||
|
|
||||||
|
@property (nonatomic) std::function<facebook::react::UIManagerInstaller> uiManagerInstaller;
|
||||||
|
@property (nonatomic) std::function<facebook::react::UIManagerUninstaller> uiManagerUninstaller;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We need to expose `uiManager` for registration
|
* We need to expose `uiManager` for registration
|
||||||
* purposes. Eventually, we will move this down to C++ side.
|
* purposes. Eventually, we will move this down to C++ side.
|
||||||
|
|
|
@ -38,11 +38,12 @@ using namespace facebook::react;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation RCTSurfacePresenter {
|
@implementation RCTSurfacePresenter {
|
||||||
RCTScheduler *_scheduler;
|
RCTScheduler *_Nullable _scheduler;
|
||||||
RCTMountingManager *_mountingManager;
|
RCTMountingManager *_mountingManager;
|
||||||
RCTBridge *_bridge;
|
RCTBridge *_bridge;
|
||||||
RCTBridge *_batchedBridge;
|
RCTBridge *_batchedBridge;
|
||||||
RCTSurfaceRegistry *_surfaceRegistry;
|
RCTSurfaceRegistry *_surfaceRegistry;
|
||||||
|
SharedContextContainer _contextContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithBridge:(RCTBridge *)bridge
|
- (instancetype)initWithBridge:(RCTBridge *)bridge
|
||||||
|
@ -69,10 +70,10 @@ using namespace facebook::react;
|
||||||
void *imageLoader = (__bridge void *)[[RCTBridge currentBridge] imageLoader];
|
void *imageLoader = (__bridge void *)[[RCTBridge currentBridge] imageLoader];
|
||||||
contextContainer->registerInstance(std::make_shared<ImageManager>(imageLoader));
|
contextContainer->registerInstance(std::make_shared<ImageManager>(imageLoader));
|
||||||
|
|
||||||
_scheduler = [[RCTScheduler alloc] initWithContextContainer:contextContainer];
|
_contextContainer = contextContainer;
|
||||||
_scheduler.delegate = self;
|
|
||||||
|
|
||||||
_surfaceRegistry = [[RCTSurfaceRegistry alloc] init];
|
_surfaceRegistry = [[RCTSurfaceRegistry alloc] init];
|
||||||
|
|
||||||
_mountingManager = [[RCTMountingManager alloc] init];
|
_mountingManager = [[RCTMountingManager alloc] init];
|
||||||
_mountingManager.delegate = self;
|
_mountingManager.delegate = self;
|
||||||
|
|
||||||
|
@ -94,18 +95,19 @@ using namespace facebook::react;
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - RCTSchedulerDelegate
|
- (void)createSchedulerIfNeeded
|
||||||
|
|
||||||
- (void)schedulerDidFinishTransaction:(facebook::react::ShadowViewMutationList)mutations
|
|
||||||
rootTag:(ReactTag)rootTag
|
|
||||||
{
|
{
|
||||||
[_mountingManager performTransactionWithMutations:mutations
|
if (_scheduler) {
|
||||||
rootTag:rootTag];
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)schedulerDidRequestPreliminaryViewAllocationWithComponentName:(NSString *)componentName
|
_scheduler = [[RCTScheduler alloc] initWithContextContainer:_contextContainer];
|
||||||
|
_scheduler.delegate = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)ensureSchedulerDoesExist
|
||||||
{
|
{
|
||||||
[_mountingManager preliminaryCreateComponentViewWithName:componentName];
|
RCTAssert(_scheduler, @"RCTSurfacePresenter: RCTScheduler instance must be already instantiated at this point.");
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Internal Surface-dedicated Interface
|
#pragma mark - Internal Surface-dedicated Interface
|
||||||
|
@ -113,20 +115,25 @@ using namespace facebook::react;
|
||||||
- (void)registerSurface:(RCTFabricSurface *)surface
|
- (void)registerSurface:(RCTFabricSurface *)surface
|
||||||
{
|
{
|
||||||
[_surfaceRegistry registerSurface:surface];
|
[_surfaceRegistry registerSurface:surface];
|
||||||
[_scheduler registerRootTag:surface.rootTag];
|
|
||||||
[self runSurface:surface];
|
|
||||||
|
|
||||||
// FIXME: mutation MUST produce instruction for root node.
|
[self startSurface:surface];
|
||||||
[_mountingManager.componentViewRegistry dequeueComponentViewWithName:@"Root" tag:surface.rootTag];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)unregisterSurface:(RCTFabricSurface *)surface
|
- (void)unregisterSurface:(RCTFabricSurface *)surface
|
||||||
{
|
{
|
||||||
[self stopSurface:surface];
|
[self stopSurface:surface];
|
||||||
[_scheduler unregisterRootTag:surface.rootTag];
|
|
||||||
[_surfaceRegistry unregisterSurface:surface];
|
[_surfaceRegistry unregisterSurface:surface];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setProps:(NSDictionary *)props
|
||||||
|
surface:(RCTFabricSurface *)surface
|
||||||
|
{
|
||||||
|
// This implementation is suboptimal indeed but still better than nothing for now.
|
||||||
|
[self stopSurface:surface];
|
||||||
|
[self startSurface:surface];
|
||||||
|
}
|
||||||
|
|
||||||
- (RCTFabricSurface *)surfaceForRootTag:(ReactTag)rootTag
|
- (RCTFabricSurface *)surfaceForRootTag:(ReactTag)rootTag
|
||||||
{
|
{
|
||||||
return [_surfaceRegistry surfaceForRootTag:rootTag];
|
return [_surfaceRegistry surfaceForRootTag:rootTag];
|
||||||
|
@ -136,6 +143,8 @@ using namespace facebook::react;
|
||||||
maximumSize:(CGSize)maximumSize
|
maximumSize:(CGSize)maximumSize
|
||||||
surface:(RCTFabricSurface *)surface
|
surface:(RCTFabricSurface *)surface
|
||||||
{
|
{
|
||||||
|
[self ensureSchedulerDoesExist];
|
||||||
|
|
||||||
LayoutContext layoutContext;
|
LayoutContext layoutContext;
|
||||||
layoutContext.pointScaleFactor = RCTScreenScale();
|
layoutContext.pointScaleFactor = RCTScreenScale();
|
||||||
LayoutConstraints layoutConstraints = {};
|
LayoutConstraints layoutConstraints = {};
|
||||||
|
@ -151,6 +160,8 @@ using namespace facebook::react;
|
||||||
maximumSize:(CGSize)maximumSize
|
maximumSize:(CGSize)maximumSize
|
||||||
surface:(RCTFabricSurface *)surface
|
surface:(RCTFabricSurface *)surface
|
||||||
{
|
{
|
||||||
|
[self ensureSchedulerDoesExist];
|
||||||
|
|
||||||
LayoutContext layoutContext;
|
LayoutContext layoutContext;
|
||||||
layoutContext.pointScaleFactor = RCTScreenScale();
|
layoutContext.pointScaleFactor = RCTScreenScale();
|
||||||
LayoutConstraints layoutConstraints = {};
|
LayoutConstraints layoutConstraints = {};
|
||||||
|
@ -162,53 +173,101 @@ using namespace facebook::react;
|
||||||
rootTag:surface.rootTag];
|
rootTag:surface.rootTag];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)runSurface:(RCTFabricSurface *)surface
|
- (void)startSurface:(RCTFabricSurface *)surface
|
||||||
{
|
{
|
||||||
|
[_mountingManager.componentViewRegistry dequeueComponentViewWithName:@"Root" tag:surface.rootTag];
|
||||||
|
|
||||||
|
[self createSchedulerIfNeeded];
|
||||||
|
[_scheduler registerRootTag:surface.rootTag];
|
||||||
|
|
||||||
|
[self setMinimumSize:surface.minimumSize
|
||||||
|
maximumSize:surface.maximumSize
|
||||||
|
surface:surface];
|
||||||
|
|
||||||
|
// TODO: Move this down to Scheduler.
|
||||||
NSDictionary *applicationParameters = @{
|
NSDictionary *applicationParameters = @{
|
||||||
@"rootTag": @(surface.rootTag),
|
@"rootTag": @(surface.rootTag),
|
||||||
@"initialProps": surface.properties,
|
@"initialProps": surface.properties,
|
||||||
};
|
};
|
||||||
|
[self->_batchedBridge enqueueJSCall:@"AppRegistry" method:@"runApplication" args:@[surface.moduleName, applicationParameters] completion:NULL];
|
||||||
[_batchedBridge enqueueJSCall:@"AppRegistry" method:@"runApplication" args:@[surface.moduleName, applicationParameters] completion:NULL];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)stopSurface:(RCTFabricSurface *)surface
|
- (void)stopSurface:(RCTFabricSurface *)surface
|
||||||
{
|
{
|
||||||
|
// TODO: Move this down to Scheduler.
|
||||||
[_batchedBridge enqueueJSCall:@"ReactFabric" method:@"unmountComponentAtNode" args:@[@(surface.rootTag)] completion:NULL];
|
[_batchedBridge enqueueJSCall:@"ReactFabric" method:@"unmountComponentAtNode" args:@[@(surface.rootTag)] completion:NULL];
|
||||||
|
|
||||||
|
[self ensureSchedulerDoesExist];
|
||||||
|
[_scheduler unregisterRootTag:surface.rootTag];
|
||||||
|
|
||||||
|
UIView<RCTComponentViewProtocol> *rootView = [_mountingManager.componentViewRegistry componentViewByTag:surface.rootTag];
|
||||||
|
[_mountingManager.componentViewRegistry enqueueComponentViewWithName:@"Root" tag:surface.rootTag componentView:rootView];
|
||||||
|
|
||||||
|
[surface _unsetStage:(RCTSurfaceStagePrepared | RCTSurfaceStageMounted)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)startAllSurfaces
|
||||||
|
{
|
||||||
|
for (RCTFabricSurface *surface in _surfaceRegistry.enumerator) {
|
||||||
|
[self startSurface:surface];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)stopAllSurfaces
|
||||||
|
{
|
||||||
|
for (RCTFabricSurface *surface in _surfaceRegistry.enumerator) {
|
||||||
|
[self stopSurface:surface];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - RCTSchedulerDelegate
|
||||||
|
|
||||||
|
- (void)schedulerDidFinishTransaction:(facebook::react::ShadowViewMutationList)mutations
|
||||||
|
rootTag:(ReactTag)rootTag
|
||||||
|
{
|
||||||
|
RCTFabricSurface *surface = [_surfaceRegistry surfaceForRootTag:rootTag];
|
||||||
|
|
||||||
|
[surface _setStage:RCTSurfaceStagePrepared];
|
||||||
|
|
||||||
|
[_mountingManager performTransactionWithMutations:mutations
|
||||||
|
rootTag:rootTag];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)schedulerDidRequestPreliminaryViewAllocationWithComponentName:(NSString *)componentName
|
||||||
|
{
|
||||||
|
[_mountingManager preliminaryCreateComponentViewWithName:componentName];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - RCTMountingManagerDelegate
|
#pragma mark - RCTMountingManagerDelegate
|
||||||
|
|
||||||
- (void)mountingManager:(RCTMountingManager *)mountingManager willMountComponentsWithRootTag:(ReactTag)rootTag
|
- (void)mountingManager:(RCTMountingManager *)mountingManager willMountComponentsWithRootTag:(ReactTag)rootTag
|
||||||
{
|
{
|
||||||
RCTIsMainQueue();
|
RCTAssertMainQueue();
|
||||||
// TODO: Propagate state change to Surface.
|
|
||||||
|
// Does nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mountingManager:(RCTMountingManager *)mountingManager didMountComponentsWithRootTag:(ReactTag)rootTag
|
- (void)mountingManager:(RCTMountingManager *)mountingManager didMountComponentsWithRootTag:(ReactTag)rootTag
|
||||||
{
|
{
|
||||||
RCTIsMainQueue();
|
RCTAssertMainQueue();
|
||||||
|
|
||||||
RCTFabricSurface *surface = [_surfaceRegistry surfaceForRootTag:rootTag];
|
RCTFabricSurface *surface = [_surfaceRegistry surfaceForRootTag:rootTag];
|
||||||
|
RCTSurfaceStage stage = surface.stage;
|
||||||
// FIXME: Implement proper state propagation mechanism.
|
if (stage & RCTSurfaceStagePrepared) {
|
||||||
[surface _setStage:RCTSurfaceStageSurfaceDidInitialRendering];
|
// We have to progress the stage only if the preparing phase is done.
|
||||||
[surface _setStage:RCTSurfaceStageSurfaceDidInitialLayout];
|
if ([surface _setStage:RCTSurfaceStageMounted]) {
|
||||||
[surface _setStage:RCTSurfaceStageSurfaceDidInitialMounting];
|
|
||||||
|
|
||||||
UIView *rootComponentView = [_mountingManager.componentViewRegistry componentViewByTag:rootTag];
|
UIView *rootComponentView = [_mountingManager.componentViewRegistry componentViewByTag:rootTag];
|
||||||
|
|
||||||
surface.view.rootView = (RCTSurfaceRootView *)rootComponentView;
|
surface.view.rootView = (RCTSurfaceRootView *)rootComponentView;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - Bridge events
|
#pragma mark - Bridge events
|
||||||
|
|
||||||
- (void)handleBridgeWillReloadNotification:(NSNotification *)notification
|
- (void)handleBridgeWillReloadNotification:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
// TODO: Define a lifecycle contract for the pieces involved here including the scheduler, mounting manager, and
|
[self stopAllSurfaces];
|
||||||
// the surface registry. For now simply recreate the scheduler on reload.
|
_scheduler = nil;
|
||||||
// The goal is to deallocate the Scheduler and its underlying references before the JS runtime is destroyed.
|
|
||||||
_scheduler = [[RCTScheduler alloc] init];
|
|
||||||
_scheduler.delegate = self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)handleJavaScriptDidLoadNotification:(NSNotification *)notification
|
- (void)handleJavaScriptDidLoadNotification:(NSNotification *)notification
|
||||||
|
@ -216,6 +275,8 @@ using namespace facebook::react;
|
||||||
RCTBridge *bridge = notification.userInfo[@"bridge"];
|
RCTBridge *bridge = notification.userInfo[@"bridge"];
|
||||||
if (bridge != _batchedBridge) {
|
if (bridge != _batchedBridge) {
|
||||||
_batchedBridge = bridge;
|
_batchedBridge = bridge;
|
||||||
|
|
||||||
|
[self startAllSurfaces];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,6 +294,26 @@ using namespace facebook::react;
|
||||||
return _bridge;
|
return _bridge;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setUiManagerInstaller:(std::function<facebook::react::UIManagerInstaller>)uiManagerInstaller
|
||||||
|
{
|
||||||
|
_contextContainer->registerInstance(uiManagerInstaller, "uimanager-installer");
|
||||||
|
}
|
||||||
|
|
||||||
|
- (std::function<facebook::react::UIManagerInstaller>)uiManagerInstaller
|
||||||
|
{
|
||||||
|
return _contextContainer->getInstance<std::function<facebook::react::UIManagerInstaller>>("uimanager-installer");
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setUiManagerUninstaller:(std::function<facebook::react::UIManagerUninstaller>)uiManagerUninstaller
|
||||||
|
{
|
||||||
|
_contextContainer->registerInstance(uiManagerUninstaller, "uimanager-uninstaller");
|
||||||
|
}
|
||||||
|
|
||||||
|
- (std::function<facebook::react::UIManagerUninstaller>)uiManagerUninstaller
|
||||||
|
{
|
||||||
|
return _contextContainer->getInstance<std::function<facebook::react::UIManagerUninstaller>>("uimanager-uninstaller");
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation RCTBridge (RCTSurfacePresenter)
|
@implementation RCTBridge (RCTSurfacePresenter)
|
||||||
|
|
|
@ -162,8 +162,7 @@
|
||||||
_properties = [properties copy];
|
_properties = [properties copy];
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement this in RCTSurfacePresenter.
|
[_surfacePresenter setProps:properties surface:self];
|
||||||
// [_surfacePresenter setProps:properties surface:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Layout
|
#pragma mark - Layout
|
||||||
|
|
Загрузка…
Ссылка в новой задаче