Fabric: RCTSurfacePresenter & thread-safety
Summary: Instead of wrapping all public methods into The controller you requested could not be found. blocks/mutexes, RCTSurfacePresenter utilizes a different thread-safety pattern where all instance variable are granularly thread-safe. The names of all internal methods were prefixed by '_'. Reviewed By: mdvacca Differential Revision: D10033407 fbshipit-source-id: 97fd2879c879dd9ef8d9ece24e25af00f749a871
This commit is contained in:
parent
c69313fc52
commit
6af687dec5
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
#import "RCTSurfacePresenter.h"
|
#import "RCTSurfacePresenter.h"
|
||||||
|
|
||||||
|
#import <mutex>
|
||||||
|
|
||||||
#import <React/RCTAssert.h>
|
#import <React/RCTAssert.h>
|
||||||
#import <React/RCTBridge+Private.h>
|
#import <React/RCTBridge+Private.h>
|
||||||
#import <React/RCTComponentViewRegistry.h>
|
#import <React/RCTComponentViewRegistry.h>
|
||||||
|
@ -38,11 +40,12 @@ using namespace facebook::react;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation RCTSurfacePresenter {
|
@implementation RCTSurfacePresenter {
|
||||||
RCTScheduler *_Nullable _scheduler;
|
std::mutex _schedulerMutex;
|
||||||
RCTMountingManager *_mountingManager;
|
RCTScheduler *_Nullable _scheduler; // Thread-safe. Mutation of the instance variable is protected by `_schedulerMutex`.
|
||||||
RCTBridge *_bridge;
|
RCTMountingManager *_mountingManager; // Thread-safe.
|
||||||
|
RCTSurfaceRegistry *_surfaceRegistry; // Thread-safe.
|
||||||
|
RCTBridge *_bridge; // Unsafe. We are moving away from Bridge.
|
||||||
RCTBridge *_batchedBridge;
|
RCTBridge *_batchedBridge;
|
||||||
RCTSurfaceRegistry *_surfaceRegistry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithBridge:(RCTBridge *)bridge
|
- (instancetype)initWithBridge:(RCTBridge *)bridge
|
||||||
|
@ -74,10 +77,71 @@ using namespace facebook::react;
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)createSchedulerIfNeeded
|
#pragma mark - Internal Surface-dedicated Interface
|
||||||
|
|
||||||
|
- (void)registerSurface:(RCTFabricSurface *)surface
|
||||||
{
|
{
|
||||||
|
[_surfaceRegistry registerSurface:surface];
|
||||||
|
[self _startSurface:surface];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)unregisterSurface:(RCTFabricSurface *)surface
|
||||||
|
{
|
||||||
|
[self _stopSurface: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
|
||||||
|
{
|
||||||
|
return [_surfaceRegistry surfaceForRootTag:rootTag];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize
|
||||||
|
maximumSize:(CGSize)maximumSize
|
||||||
|
surface:(RCTFabricSurface *)surface
|
||||||
|
{
|
||||||
|
LayoutContext layoutContext;
|
||||||
|
layoutContext.pointScaleFactor = RCTScreenScale();
|
||||||
|
LayoutConstraints layoutConstraints = {};
|
||||||
|
layoutConstraints.minimumSize = RCTSizeFromCGSize(minimumSize);
|
||||||
|
layoutConstraints.maximumSize = RCTSizeFromCGSize(maximumSize);
|
||||||
|
|
||||||
|
return [self._scheduler measureSurfaceWithLayoutConstraints:layoutConstraints
|
||||||
|
layoutContext:layoutContext
|
||||||
|
surfaceId:surface.rootTag];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setMinimumSize:(CGSize)minimumSize
|
||||||
|
maximumSize:(CGSize)maximumSize
|
||||||
|
surface:(RCTFabricSurface *)surface
|
||||||
|
{
|
||||||
|
LayoutContext layoutContext;
|
||||||
|
layoutContext.pointScaleFactor = RCTScreenScale();
|
||||||
|
LayoutConstraints layoutConstraints = {};
|
||||||
|
layoutConstraints.minimumSize = RCTSizeFromCGSize(minimumSize);
|
||||||
|
layoutConstraints.maximumSize = RCTSizeFromCGSize(maximumSize);
|
||||||
|
|
||||||
|
[self._scheduler constraintSurfaceLayoutWithLayoutConstraints:layoutConstraints
|
||||||
|
layoutContext:layoutContext
|
||||||
|
surfaceId:surface.rootTag];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Private
|
||||||
|
|
||||||
|
- (RCTScheduler *)_scheduler
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(_schedulerMutex);
|
||||||
|
|
||||||
if (_scheduler) {
|
if (_scheduler) {
|
||||||
return;
|
return _scheduler;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto contextContainer = std::make_shared<ContextContainer>();
|
auto contextContainer = std::make_shared<ContextContainer>();
|
||||||
|
@ -102,96 +166,26 @@ using namespace facebook::react;
|
||||||
|
|
||||||
_scheduler = [[RCTScheduler alloc] initWithContextContainer:contextContainer];
|
_scheduler = [[RCTScheduler alloc] initWithContextContainer:contextContainer];
|
||||||
_scheduler.delegate = self;
|
_scheduler.delegate = self;
|
||||||
|
|
||||||
|
return _scheduler;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)ensureSchedulerDoesExist
|
- (void)_startSurface:(RCTFabricSurface *)surface
|
||||||
{
|
|
||||||
RCTAssert(_scheduler, @"RCTSurfacePresenter: RCTScheduler instance must be already instantiated at this point.");
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Internal Surface-dedicated Interface
|
|
||||||
|
|
||||||
- (void)registerSurface:(RCTFabricSurface *)surface
|
|
||||||
{
|
|
||||||
[_surfaceRegistry registerSurface:surface];
|
|
||||||
|
|
||||||
[self startSurface:surface];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)unregisterSurface:(RCTFabricSurface *)surface
|
|
||||||
{
|
|
||||||
[self stopSurface: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
|
|
||||||
{
|
|
||||||
return [_surfaceRegistry surfaceForRootTag:rootTag];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize
|
|
||||||
maximumSize:(CGSize)maximumSize
|
|
||||||
surface:(RCTFabricSurface *)surface
|
|
||||||
{
|
|
||||||
[self ensureSchedulerDoesExist];
|
|
||||||
|
|
||||||
LayoutContext layoutContext;
|
|
||||||
layoutContext.pointScaleFactor = RCTScreenScale();
|
|
||||||
LayoutConstraints layoutConstraints = {};
|
|
||||||
layoutConstraints.minimumSize = RCTSizeFromCGSize(minimumSize);
|
|
||||||
layoutConstraints.maximumSize = RCTSizeFromCGSize(maximumSize);
|
|
||||||
|
|
||||||
return [_scheduler measureSurfaceWithLayoutConstraints:layoutConstraints
|
|
||||||
layoutContext:layoutContext
|
|
||||||
surfaceId:surface.rootTag];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setMinimumSize:(CGSize)minimumSize
|
|
||||||
maximumSize:(CGSize)maximumSize
|
|
||||||
surface:(RCTFabricSurface *)surface
|
|
||||||
{
|
|
||||||
[self ensureSchedulerDoesExist];
|
|
||||||
|
|
||||||
LayoutContext layoutContext;
|
|
||||||
layoutContext.pointScaleFactor = RCTScreenScale();
|
|
||||||
LayoutConstraints layoutConstraints = {};
|
|
||||||
layoutConstraints.minimumSize = RCTSizeFromCGSize(minimumSize);
|
|
||||||
layoutConstraints.maximumSize = RCTSizeFromCGSize(maximumSize);
|
|
||||||
|
|
||||||
[_scheduler constraintSurfaceLayoutWithLayoutConstraints:layoutConstraints
|
|
||||||
layoutContext:layoutContext
|
|
||||||
surfaceId:surface.rootTag];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)startSurface:(RCTFabricSurface *)surface
|
|
||||||
{
|
{
|
||||||
[_mountingManager.componentViewRegistry dequeueComponentViewWithName:@"Root" tag:surface.rootTag];
|
[_mountingManager.componentViewRegistry dequeueComponentViewWithName:@"Root" tag:surface.rootTag];
|
||||||
|
|
||||||
[self createSchedulerIfNeeded];
|
[self._scheduler startSurfaceWithSurfaceId:surface.rootTag
|
||||||
|
moduleName:surface.moduleName
|
||||||
[_scheduler startSurfaceWithSurfaceId:surface.rootTag
|
initailProps:surface.properties];
|
||||||
moduleName:surface.moduleName
|
|
||||||
initailProps:surface.properties];
|
|
||||||
|
|
||||||
[self setMinimumSize:surface.minimumSize
|
[self setMinimumSize:surface.minimumSize
|
||||||
maximumSize:surface.maximumSize
|
maximumSize:surface.maximumSize
|
||||||
surface:surface];
|
surface:surface];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)stopSurface:(RCTFabricSurface *)surface
|
- (void)_stopSurface:(RCTFabricSurface *)surface
|
||||||
{
|
{
|
||||||
[self ensureSchedulerDoesExist];
|
[self._scheduler stopSurfaceWithSurfaceId:surface.rootTag];
|
||||||
|
|
||||||
[_scheduler stopSurfaceWithSurfaceId:surface.rootTag];
|
|
||||||
|
|
||||||
UIView<RCTComponentViewProtocol> *rootView = [_mountingManager.componentViewRegistry componentViewByTag:surface.rootTag];
|
UIView<RCTComponentViewProtocol> *rootView = [_mountingManager.componentViewRegistry componentViewByTag:surface.rootTag];
|
||||||
[_mountingManager.componentViewRegistry enqueueComponentViewWithName:@"Root" tag:surface.rootTag componentView:rootView];
|
[_mountingManager.componentViewRegistry enqueueComponentViewWithName:@"Root" tag:surface.rootTag componentView:rootView];
|
||||||
|
@ -199,17 +193,17 @@ using namespace facebook::react;
|
||||||
[surface _unsetStage:(RCTSurfaceStagePrepared | RCTSurfaceStageMounted)];
|
[surface _unsetStage:(RCTSurfaceStagePrepared | RCTSurfaceStageMounted)];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)startAllSurfaces
|
- (void)_startAllSurfaces
|
||||||
{
|
{
|
||||||
for (RCTFabricSurface *surface in _surfaceRegistry.enumerator) {
|
for (RCTFabricSurface *surface in _surfaceRegistry.enumerator) {
|
||||||
[self startSurface:surface];
|
[self _startSurface:surface];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)stopAllSurfaces
|
- (void)_stopAllSurfaces
|
||||||
{
|
{
|
||||||
for (RCTFabricSurface *surface in _surfaceRegistry.enumerator) {
|
for (RCTFabricSurface *surface in _surfaceRegistry.enumerator) {
|
||||||
[self stopSurface:surface];
|
[self _stopSurface:surface];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,8 +253,20 @@ using namespace facebook::react;
|
||||||
|
|
||||||
- (void)handleBridgeWillReloadNotification:(NSNotification *)notification
|
- (void)handleBridgeWillReloadNotification:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
[self stopAllSurfaces];
|
{
|
||||||
_scheduler = nil;
|
std::lock_guard<std::mutex> lock(_schedulerMutex);
|
||||||
|
if (!_scheduler) {
|
||||||
|
// Seems we are already in the realoding process.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[self _stopAllSurfaces];
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(_schedulerMutex);
|
||||||
|
_scheduler = nil;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)handleJavaScriptDidLoadNotification:(NSNotification *)notification
|
- (void)handleJavaScriptDidLoadNotification:(NSNotification *)notification
|
||||||
|
@ -269,7 +275,7 @@ using namespace facebook::react;
|
||||||
if (bridge != _batchedBridge) {
|
if (bridge != _batchedBridge) {
|
||||||
_batchedBridge = bridge;
|
_batchedBridge = bridge;
|
||||||
|
|
||||||
[self startAllSurfaces];
|
[self _startAllSurfaces];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue