From 7420048b63429c066ff6869279e77e3bf52e4ab7 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Wed, 26 Sep 2018 10:01:54 -0700 Subject: [PATCH] Fabric: RCTSurface's start and stop methods Summary: The original design of RCTSurface implied that the Surface starts on initialization and stops on deallocation. Recently I realized that this not sufficient API in some cases when the application uses ARC with autorelease pools (that can postpone object deallocations, which is highly undesirable). And that's simply handy to have those methods sometimes. Reviewed By: mdvacca Differential Revision: D9982356 fbshipit-source-id: baa3bd24804d3708606ebd00b8795f2d5c9d4de9 --- React/Base/Surface/RCTSurface.h | 9 ++++++ React/Base/Surface/RCTSurface.mm | 14 ++++++++++ React/Base/Surface/RCTSurfaceStage.h | 2 ++ .../RCTSurfaceHostingView.mm | 6 ++++ React/Fabric/Surface/RCTFabricSurface.h | 16 +++++++++++ React/Fabric/Surface/RCTFabricSurface.mm | 28 ++++++++++++++++--- 6 files changed, 71 insertions(+), 4 deletions(-) diff --git a/React/Base/Surface/RCTSurface.h b/React/Base/Surface/RCTSurface.h index 759e60cdf..cb3772af4 100644 --- a/React/Base/Surface/RCTSurface.h +++ b/React/Base/Surface/RCTSurface.h @@ -114,6 +114,15 @@ NS_ASSUME_NONNULL_BEGIN */ - (BOOL)synchronouslyWaitForStage:(RCTSurfaceStage)stage timeout:(NSTimeInterval)timeout; +#pragma mark - Start & Stop + +/** + * Starts or stops the Surface. + * Those methods are not implemented yet for regular RCTSurface. + */ +- (BOOL)start; +- (BOOL)stop; + #pragma mark - Mounting/Unmounting of React components /** diff --git a/React/Base/Surface/RCTSurface.mm b/React/Base/Surface/RCTSurface.mm index 8a2d0b99b..8b62fea66 100644 --- a/React/Base/Surface/RCTSurface.mm +++ b/React/Base/Surface/RCTSurface.mm @@ -560,6 +560,20 @@ } } +- (BOOL)start +{ + // Does nothing. + // The Start&Stop feature is not implemented for regular Surface yet. + return YES; +} + +- (BOOL)stop +{ + // Does nothing. + // The Start&Stop feature is not implemented for regular Surface yet. + return YES; +} + #pragma mark - Mounting/Unmounting of React components - (void)mountReactComponentWithBridge:(RCTBridge *)bridge moduleName:(NSString *)moduleName params:(NSDictionary *)params diff --git a/React/Base/Surface/RCTSurfaceStage.h b/React/Base/Surface/RCTSurfaceStage.h index b79d6b3cb..354cf850f 100644 --- a/React/Base/Surface/RCTSurfaceStage.h +++ b/React/Base/Surface/RCTSurfaceStage.h @@ -27,6 +27,8 @@ typedef NS_OPTIONS(NSInteger, RCTSurfaceStage) { // // Surface object was constructed and still valid. RCTSurfaceStageInitialized = RCTSurfaceStageSurfaceDidInitialize, + // Surface was started. + RCTSurfaceStageStarted = 1 << 8, // All off-main-thread work is done; we are ready to mount the UI. RCTSurfaceStagePrepared = RCTSurfaceStageBridgeDidLoad | RCTSurfaceStageModuleDidLoad | RCTSurfaceStageSurfaceDidRun | RCTSurfaceStageSurfaceDidInitialRendering | RCTSurfaceStageSurfaceDidInitialLayout, // All main-thread work is done, the UI was mounted. diff --git a/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm b/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm index 3d5cf7546..f3d999d97 100644 --- a/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm +++ b/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm @@ -50,6 +50,7 @@ RCT_NOT_IMPLEMENTED(- (nullable instancetype)initWithCoder:(NSCoder *)coder) { if (self = [super initWithFrame:CGRectZero]) { _surface = surface; + [_surface start]; _sizeMeasureMode = sizeMeasureMode; _surface.delegate = self; @@ -60,6 +61,11 @@ RCT_NOT_IMPLEMENTED(- (nullable instancetype)initWithCoder:(NSCoder *)coder) return self; } +- (void)dealloc +{ + [_surface stop]; +} + - (void)setFrame:(CGRect)frame { [super setFrame:frame]; diff --git a/React/Fabric/Surface/RCTFabricSurface.h b/React/Fabric/Surface/RCTFabricSurface.h index 2deeae736..41ca6e589 100644 --- a/React/Fabric/Surface/RCTFabricSurface.h +++ b/React/Fabric/Surface/RCTFabricSurface.h @@ -63,6 +63,22 @@ NS_ASSUME_NONNULL_BEGIN */ - (RCTSurfaceView *)view; +#pragma mark - Start & Stop + +/** + * Starts or stops the Surface. + * A Surface object can be stopped and then restarted. + * The starting process includes initializing all underlying React Native + * infrastructure and running React app. + * Just initialized Surface object starts automatically, there is no need + * to call `start` explicitly. Surface also stops itself on deallocation + * automatically. + * Returns YES in case of success. Returns NO if the Surface is already + * started or stopped. + */ +- (BOOL)start; +- (BOOL)stop; + #pragma mark - Layout: Setting the size constrains /** diff --git a/React/Fabric/Surface/RCTFabricSurface.mm b/React/Fabric/Surface/RCTFabricSurface.mm index ae68f1806..fb238f31f 100644 --- a/React/Fabric/Surface/RCTFabricSurface.mm +++ b/React/Fabric/Surface/RCTFabricSurface.mm @@ -51,19 +51,39 @@ _minimumSize = CGSizeZero; _maximumSize = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX); - _stage = RCTSurfaceStageSurfaceDidInitialize; - _touchHandler = [RCTSurfaceTouchHandler new]; - [_surfacePresenter registerSurface:self]; + _stage = RCTSurfaceStageSurfaceDidInitialize; + + [self start]; } return self; } +- (BOOL)start +{ + if (![self _setStage:RCTSurfaceStageStarted]) { + return NO; + } + + [_surfacePresenter registerSurface:self]; + return YES; +} + +- (BOOL)stop +{ + if (![self _unsetStage:RCTSurfaceStageStarted]) { + return NO; + } + + [_surfacePresenter unregisterSurface:self]; + return YES; +} + - (void)dealloc { - [_surfacePresenter unregisterSurface:self]; + [self stop]; } #pragma mark - Immutable Properties (no need to enforce synchonization)