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:
Valentin Shergin 2018-09-26 10:01:42 -07:00 коммит произвёл Facebook Github Bot
Родитель 24ffd8f6fb
Коммит bce94dc8c3
3 изменённых файлов: 124 добавлений и 38 удалений

Просмотреть файл

@ -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