diff --git a/React/Fabric/Mounting/MountItems/RCTCreateMountItem.h b/React/Fabric/Mounting/MountItems/RCTCreateMountItem.h index a96968044..344fd1ab7 100644 --- a/React/Fabric/Mounting/MountItems/RCTCreateMountItem.h +++ b/React/Fabric/Mounting/MountItems/RCTCreateMountItem.h @@ -7,6 +7,7 @@ #import +#import #import #import @@ -19,8 +20,8 @@ NS_ASSUME_NONNULL_BEGIN */ @interface RCTCreateMountItem : NSObject -- (instancetype)initWithComponentName:(NSString *)componentName - tag:(ReactTag)tag; +- (instancetype)initWithComponentHandle:(facebook::react::ComponentHandle)componentHandle + tag:(ReactTag)tag; @end diff --git a/React/Fabric/Mounting/MountItems/RCTCreateMountItem.mm b/React/Fabric/Mounting/MountItems/RCTCreateMountItem.mm index e51642952..a91f0194c 100644 --- a/React/Fabric/Mounting/MountItems/RCTCreateMountItem.mm +++ b/React/Fabric/Mounting/MountItems/RCTCreateMountItem.mm @@ -9,16 +9,18 @@ #import "RCTComponentViewRegistry.h" +using namespace facebook::react; + @implementation RCTCreateMountItem { - NSString *_componentName; + ComponentHandle _componentHandle; ReactTag _tag; } -- (instancetype)initWithComponentName:(NSString *)componentName - tag:(ReactTag)tag +- (instancetype)initWithComponentHandle:(facebook::react::ComponentHandle)componentHandle + tag:(ReactTag)tag { if (self = [super init]) { - _componentName = componentName; + _componentHandle = componentHandle; _tag = tag; } @@ -27,7 +29,7 @@ - (void)executeWithRegistry:(RCTComponentViewRegistry *)registry { - [registry dequeueComponentViewWithName:_componentName tag:_tag]; + [registry dequeueComponentViewWithComponentHandle:_componentHandle tag:_tag]; } @end diff --git a/React/Fabric/Mounting/MountItems/RCTDeleteMountItem.h b/React/Fabric/Mounting/MountItems/RCTDeleteMountItem.h index 1907023e1..f0d07b47c 100644 --- a/React/Fabric/Mounting/MountItems/RCTDeleteMountItem.h +++ b/React/Fabric/Mounting/MountItems/RCTDeleteMountItem.h @@ -7,6 +7,7 @@ #import +#import #import #import @@ -17,8 +18,8 @@ NS_ASSUME_NONNULL_BEGIN */ @interface RCTDeleteMountItem : NSObject -- (instancetype)initWithComponentName:(NSString *)componentName - tag:(ReactTag)tag; +- (instancetype)initWithComponentHandle:(facebook::react::ComponentHandle)componentHandle + tag:(ReactTag)tag; @end diff --git a/React/Fabric/Mounting/MountItems/RCTDeleteMountItem.mm b/React/Fabric/Mounting/MountItems/RCTDeleteMountItem.mm index c45fba617..9528d60ca 100644 --- a/React/Fabric/Mounting/MountItems/RCTDeleteMountItem.mm +++ b/React/Fabric/Mounting/MountItems/RCTDeleteMountItem.mm @@ -9,16 +9,18 @@ #import "RCTComponentViewRegistry.h" +using namespace facebook::react; + @implementation RCTDeleteMountItem { - NSString *_componentName; + ComponentHandle _componentHandle; ReactTag _tag; } -- (instancetype)initWithComponentName:(NSString *)componentName - tag:(ReactTag)tag +- (instancetype)initWithComponentHandle:(facebook::react::ComponentHandle)componentHandle + tag:(ReactTag)tag { if (self = [super init]) { - _componentName = componentName; + _componentHandle = componentHandle; _tag = tag; } @@ -33,7 +35,7 @@ return; } - [registry enqueueComponentViewWithName:_componentName tag:_tag componentView:componentView]; + [registry enqueueComponentViewWithComponentHandle:_componentHandle tag:_tag componentView:componentView]; } @end diff --git a/React/Fabric/Mounting/RCTComponentViewFactory.h b/React/Fabric/Mounting/RCTComponentViewFactory.h new file mode 100644 index 000000000..1aed476a1 --- /dev/null +++ b/React/Fabric/Mounting/RCTComponentViewFactory.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * Registry of supported component view classes that can instantiate + * view component instances by given component handle. + */ +@interface RCTComponentViewFactory : NSObject + +/** + * Constructs and returns an instance of the class with a bunch of already registered standard components. + */ ++ (RCTComponentViewFactory *)standardComponentViewFactory; + +/** + * Registers a component view class in the factory. + */ +- (void)registerComponentViewClass:(Class)componentViewClass; + +/** + * Creates a component view with given component handle. + */ +- (UIView *)createComponentViewWithComponentHandle:(facebook::react::ComponentHandle)componentHandle; + +@end + +NS_ASSUME_NONNULL_END diff --git a/React/Fabric/Mounting/RCTComponentViewFactory.mm b/React/Fabric/Mounting/RCTComponentViewFactory.mm new file mode 100644 index 000000000..817f65657 --- /dev/null +++ b/React/Fabric/Mounting/RCTComponentViewFactory.mm @@ -0,0 +1,65 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTComponentViewFactory.h" + +#import +#import + +#import "RCTViewComponentView.h" +#import "RCTImageComponentView.h" +#import "RCTScrollViewComponentView.h" +#import "RCTParagraphComponentView.h" +#import "RCTRootComponentView.h" +#import "RCTActivityIndicatorViewComponentView.h" +#import "RCTSwitchComponentView.h" + +using namespace facebook::react; + +@implementation RCTComponentViewFactory +{ + std::unordered_map> _registry; +} + ++ (RCTComponentViewFactory *)standardComponentViewFactory +{ + RCTAssertMainQueue(); + + RCTComponentViewFactory *componentViewFactory = [[RCTComponentViewFactory alloc] init]; + + [componentViewFactory registerComponentViewClass:[RCTViewComponentView class]]; + [componentViewFactory registerComponentViewClass:[RCTRootComponentView class]]; + [componentViewFactory registerComponentViewClass:[RCTScrollViewComponentView class]]; + [componentViewFactory registerComponentViewClass:[RCTImageComponentView class]]; + [componentViewFactory registerComponentViewClass:[RCTParagraphComponentView class]]; + [componentViewFactory registerComponentViewClass:[RCTActivityIndicatorViewComponentView class]]; + [componentViewFactory registerComponentViewClass:[RCTSwitchComponentView class]]; + + return componentViewFactory; +} + +- (void)registerComponentViewClass:(Class)componentViewClass +{ + RCTAssertMainQueue(); + + ComponentHandle componentHandle = [componentViewClass componentHandle]; + _registry[componentHandle] = componentViewClass; +} + +- (UIView *)createComponentViewWithComponentHandle:(facebook::react::ComponentHandle)componentHandle +{ + RCTAssertMainQueue(); + + auto iterator = _registry.find(componentHandle); + RCTAssert( + iterator != _registry.end(), + @"ComponentView with componentHandle `%lli` (`%s`) not found.", componentHandle, (char *)componentHandle); + Class componentViewClass = iterator->second; + return [[componentViewClass alloc] init]; +} + +@end diff --git a/React/Fabric/Mounting/RCTComponentViewRegistry.h b/React/Fabric/Mounting/RCTComponentViewRegistry.h index ba32ec648..127c1e5c7 100644 --- a/React/Fabric/Mounting/RCTComponentViewRegistry.h +++ b/React/Fabric/Mounting/RCTComponentViewRegistry.h @@ -7,6 +7,8 @@ #import +#import +#import #import NS_ASSUME_NONNULL_BEGIN @@ -17,21 +19,23 @@ NS_ASSUME_NONNULL_BEGIN */ @interface RCTComponentViewRegistry : NSObject +@property (nonatomic, strong, readonly) RCTComponentViewFactory *componentViewFactory; + /** * Returns a native view instance from the recycle pool (or create) - * for given `componentName` and with given `tag`. + * for given `componentHandle` and with given `tag`. * #RefuseSingleUse */ -- (UIView *)dequeueComponentViewWithName:(NSString *)componentName - tag:(ReactTag)tag; +- (UIView *)dequeueComponentViewWithComponentHandle:(facebook::react::ComponentHandle)componentHandle + tag:(ReactTag)tag; /** * Puts a given native component view to the recycle pool. * #RefuseSingleUse */ -- (void)enqueueComponentViewWithName:(NSString *)componentName - tag:(ReactTag)tag - componentView:(UIView *)componentView; +- (void)enqueueComponentViewWithComponentHandle:(facebook::react::ComponentHandle)componentHandle + tag:(ReactTag)tag + componentView:(UIView *)componentView; /** * Returns a native component view by given `tag`. @@ -46,7 +50,7 @@ NS_ASSUME_NONNULL_BEGIN /** * Creates a component view with a given type and puts it to the recycle pool. */ -- (void)preliminaryCreateComponentViewWithName:(NSString *)componentName; +- (void)optimisticallyCreateComponentViewWithComponentHandle:(facebook::react::ComponentHandle)componentHandle; @end diff --git a/React/Fabric/Mounting/RCTComponentViewRegistry.mm b/React/Fabric/Mounting/RCTComponentViewRegistry.mm index f6374a27f..c5e156390 100644 --- a/React/Fabric/Mounting/RCTComponentViewRegistry.mm +++ b/React/Fabric/Mounting/RCTComponentViewRegistry.mm @@ -10,6 +10,8 @@ #import #import +using namespace facebook::react; + #define LEGACY_UIMANAGER_INTEGRATION_ENABLED 1 #ifdef LEGACY_UIMANAGER_INTEGRATION_ENABLED @@ -67,8 +69,8 @@ const NSInteger RCTComponentViewRegistryRecyclePoolMaxSize = 1024; @implementation RCTComponentViewRegistry { - NSMapTable *> *_registry; - NSMapTable *> *> *_recyclePool; + NSMapTable *> *_registry; + NSMapTable *> *> *_recyclePool; } - (instancetype)init @@ -76,15 +78,16 @@ const NSInteger RCTComponentViewRegistryRecyclePoolMaxSize = 1024; if (self = [super init]) { _registry = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsIntegerPersonality | NSPointerFunctionsOpaqueMemory valueOptions:NSPointerFunctionsObjectPersonality]; - _recyclePool = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsObjectPersonality + _recyclePool = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsOpaquePersonality | NSPointerFunctionsOpaqueMemory valueOptions:NSPointerFunctionsObjectPersonality]; + _componentViewFactory = [RCTComponentViewFactory standardComponentViewFactory]; } return self; } -- (UIView *)dequeueComponentViewWithName:(NSString *)componentName - tag:(ReactTag)tag +- (UIView *)dequeueComponentViewWithComponentHandle:(ComponentHandle)componentHandle + tag:(ReactTag)tag { RCTAssertMainQueue(); @@ -92,7 +95,7 @@ const NSInteger RCTComponentViewRegistryRecyclePoolMaxSize = 1024; @"RCTComponentViewRegistry: Attempt to dequeue already registered component."); UIView *componentView = - [self _dequeueComponentViewWithName:componentName]; + [self _dequeueComponentViewWithComponentHandle:componentHandle]; componentView.tag = tag; [_registry setObject:componentView forKey:(__bridge id)(void *)tag]; @@ -103,9 +106,9 @@ const NSInteger RCTComponentViewRegistryRecyclePoolMaxSize = 1024; return componentView; } -- (void)enqueueComponentViewWithName:(NSString *)componentName - tag:(ReactTag)tag - componentView:(UIView *)componentView +- (void)enqueueComponentViewWithComponentHandle:(ComponentHandle)componentHandle + tag:(ReactTag)tag + componentView:(UIView *)componentView { RCTAssertMainQueue(); @@ -118,14 +121,14 @@ const NSInteger RCTComponentViewRegistryRecyclePoolMaxSize = 1024; [_registry removeObjectForKey:(__bridge id)(void *)tag]; componentView.tag = 0; - [self _enqueueComponentViewWithName:componentName componentView:componentView]; + [self _enqueueComponentViewWithComponentHandle:componentHandle componentView:componentView]; } -- (void)preliminaryCreateComponentViewWithName:(NSString *)componentName +- (void)optimisticallyCreateComponentViewWithComponentHandle:(ComponentHandle)componentHandle { RCTAssertMainQueue(); - [self _enqueueComponentViewWithName:componentName - componentView:[self _createComponentViewWithName:componentName]]; + [self _enqueueComponentViewWithComponentHandle:componentHandle + componentView:[self.componentViewFactory createComponentViewWithComponentHandle:componentHandle]]; } - (UIView *)componentViewByTag:(ReactTag)tag @@ -140,21 +143,13 @@ const NSInteger RCTComponentViewRegistryRecyclePoolMaxSize = 1024; return componentView.tag; } -- (UIView *)_createComponentViewWithName:(NSString *)componentName +- (nullable UIView *)_dequeueComponentViewWithComponentHandle:(ComponentHandle)componentHandle { RCTAssertMainQueue(); - // This is temporary approach. - NSString *className = [NSString stringWithFormat:@"RCT%@ComponentView", componentName]; - UIView *componentView = [[NSClassFromString(className) alloc] init]; - return componentView; -} - -- (nullable UIView *)_dequeueComponentViewWithName:(NSString *)componentName -{ - RCTAssertMainQueue(); - NSHashTable *> *componentViews = [_recyclePool objectForKey:componentName]; + NSHashTable *> *componentViews = + [_recyclePool objectForKey:(__bridge id)(void *)componentHandle]; if (!componentViews || componentViews.count == 0) { - return [self _createComponentViewWithName:componentName]; + return [self.componentViewFactory createComponentViewWithComponentHandle:componentHandle]; } UIView *componentView = [componentViews anyObject]; @@ -162,16 +157,17 @@ const NSInteger RCTComponentViewRegistryRecyclePoolMaxSize = 1024; return componentView; } -- (void)_enqueueComponentViewWithName:(NSString *)componentName - componentView:(UIView *)componentView +- (void)_enqueueComponentViewWithComponentHandle:(ComponentHandle)componentHandle + componentView:(UIView *)componentView { RCTAssertMainQueue(); [componentView prepareForRecycle]; - NSHashTable *> *componentViews = [_recyclePool objectForKey:componentName]; + NSHashTable *> *componentViews = + [_recyclePool objectForKey:(__bridge id)(void *)componentHandle]; if (!componentViews) { componentViews = [NSHashTable hashTableWithOptions:NSPointerFunctionsObjectPersonality]; - [_recyclePool setObject:componentViews forKey:componentName]; + [_recyclePool setObject:componentViews forKey:(__bridge id)(void *)componentHandle]; } if (componentViews.count >= RCTComponentViewRegistryRecyclePoolMaxSize) { diff --git a/React/Fabric/Mounting/RCTMountingManager.h b/React/Fabric/Mounting/RCTMountingManager.h index 600d33c86..68ed226d0 100644 --- a/React/Fabric/Mounting/RCTMountingManager.h +++ b/React/Fabric/Mounting/RCTMountingManager.h @@ -7,6 +7,7 @@ #import +#import #import #import #import @@ -37,7 +38,7 @@ NS_ASSUME_NONNULL_BEGIN * The receiver is free to ignore the request. * Can be called from any thread. */ -- (void)preliminaryCreateComponentViewWithName:(NSString *)componentName; +- (void)optimisticallyCreateComponentViewWithComponentHandle:(facebook::react::ComponentHandle)componentHandle; @end diff --git a/React/Fabric/Mounting/RCTMountingManager.mm b/React/Fabric/Mounting/RCTMountingManager.mm index c018d0fbb..3b7a1a23b 100644 --- a/React/Fabric/Mounting/RCTMountingManager.mm +++ b/React/Fabric/Mounting/RCTMountingManager.mm @@ -47,19 +47,17 @@ using namespace facebook::react; for (const auto &mutation : mutations) { switch (mutation.type) { case ShadowViewMutation::Create: { - NSString *componentName = RCTNSStringFromString(mutation.newChildShadowView.componentName, NSASCIIStringEncoding); RCTCreateMountItem *mountItem = - [[RCTCreateMountItem alloc] initWithComponentName:componentName - tag:mutation.newChildShadowView.tag]; + [[RCTCreateMountItem alloc] initWithComponentHandle:mutation.newChildShadowView.componentHandle + tag:mutation.newChildShadowView.tag]; [mountItems addObject:mountItem]; break; } case ShadowViewMutation::Delete: { - NSString *componentName = RCTNSStringFromString(mutation.oldChildShadowView.componentName, NSASCIIStringEncoding); RCTDeleteMountItem *mountItem = - [[RCTDeleteMountItem alloc] initWithComponentName:componentName - tag:mutation.oldChildShadowView.tag]; + [[RCTDeleteMountItem alloc] initWithComponentHandle:mutation.oldChildShadowView.componentHandle + tag:mutation.oldChildShadowView.tag]; [mountItems addObject:mountItem]; break; } @@ -170,10 +168,10 @@ using namespace facebook::react; [self.delegate mountingManager:self didMountComponentsWithRootTag:rootTag]; } -- (void)preliminaryCreateComponentViewWithName:(NSString *)componentName +- (void)optimisticallyCreateComponentViewWithComponentHandle:(ComponentHandle)componentHandle { RCTExecuteOnMainQueue(^{ - [self->_componentViewRegistry preliminaryCreateComponentViewWithName:componentName]; + [self->_componentViewRegistry optimisticallyCreateComponentViewWithComponentHandle:componentHandle]; }); } diff --git a/React/Fabric/RCTScheduler.h b/React/Fabric/RCTScheduler.h index 9a80af8ec..ff3baa318 100644 --- a/React/Fabric/RCTScheduler.h +++ b/React/Fabric/RCTScheduler.h @@ -25,7 +25,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)schedulerDidFinishTransaction:(facebook::react::ShadowViewMutationList)mutations rootTag:(ReactTag)rootTag; -- (void)schedulerDidRequestPreliminaryViewAllocationWithComponentName:(NSString *)componentName; +- (void)schedulerOptimisticallyCreateComponentViewWithComponentHandle:(facebook::react::ComponentHandle)componentHandle; @end diff --git a/React/Fabric/RCTScheduler.mm b/React/Fabric/RCTScheduler.mm index 7c65f1c6f..8276a68c9 100644 --- a/React/Fabric/RCTScheduler.mm +++ b/React/Fabric/RCTScheduler.mm @@ -29,7 +29,7 @@ public: void schedulerDidRequestPreliminaryViewAllocation(SurfaceId surfaceId, ComponentName componentName, bool isLayoutable, ComponentHandle componentHandle) override { RCTScheduler *scheduler = (__bridge RCTScheduler *)scheduler_; - [scheduler.delegate schedulerDidRequestPreliminaryViewAllocationWithComponentName:RCTNSStringFromString(componentName, NSASCIIStringEncoding)]; + [scheduler.delegate schedulerOptimisticallyCreateComponentViewWithComponentHandle:componentHandle]; } private: diff --git a/React/Fabric/RCTSurfacePresenter.h b/React/Fabric/RCTSurfacePresenter.h index d95c57bc1..c3eeacd32 100644 --- a/React/Fabric/RCTSurfacePresenter.h +++ b/React/Fabric/RCTSurfacePresenter.h @@ -9,6 +9,7 @@ #import #import +#import #import NS_ASSUME_NONNULL_BEGIN @@ -26,6 +27,8 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithBridge:(RCTBridge *)bridge; +@property (nonatomic, readonly) RCTComponentViewFactory *componentViewFactory; + @end @interface RCTSurfacePresenter (Surface) diff --git a/React/Fabric/RCTSurfacePresenter.mm b/React/Fabric/RCTSurfacePresenter.mm index 1b8a92110..1ad7a3464 100644 --- a/React/Fabric/RCTSurfacePresenter.mm +++ b/React/Fabric/RCTSurfacePresenter.mm @@ -26,6 +26,7 @@ #import #import #import +#import #import #import @@ -80,6 +81,11 @@ using namespace facebook::react; [[NSNotificationCenter defaultCenter] removeObserver:self]; } +- (RCTComponentViewFactory *)componentViewFactory +{ + return _mountingManager.componentViewRegistry.componentViewFactory; +} + #pragma mark - Internal Surface-dedicated Interface - (void)registerSurface:(RCTFabricSurface *)surface @@ -188,7 +194,8 @@ using namespace facebook::react; - (void)_startSurface:(RCTFabricSurface *)surface { - [_mountingManager.componentViewRegistry dequeueComponentViewWithName:@"Root" tag:surface.rootTag]; + [_mountingManager.componentViewRegistry dequeueComponentViewWithComponentHandle:RootShadowNode::Handle() + tag:surface.rootTag]; LayoutContext layoutContext = { .pointScaleFactor = RCTScreenScale() @@ -210,8 +217,11 @@ using namespace facebook::react; { [self._scheduler stopSurfaceWithSurfaceId:surface.rootTag]; - UIView *rootView = [_mountingManager.componentViewRegistry componentViewByTag:surface.rootTag]; - [_mountingManager.componentViewRegistry enqueueComponentViewWithName:@"Root" tag:surface.rootTag componentView:rootView]; + UIView *rootView = + [_mountingManager.componentViewRegistry componentViewByTag:surface.rootTag]; + [_mountingManager.componentViewRegistry enqueueComponentViewWithComponentHandle:RootShadowNode::Handle() + tag:surface.rootTag + componentView:rootView]; [surface _unsetStage:(RCTSurfaceStagePrepared | RCTSurfaceStageMounted)]; } @@ -243,9 +253,9 @@ using namespace facebook::react; rootTag:rootTag]; } -- (void)schedulerDidRequestPreliminaryViewAllocationWithComponentName:(NSString *)componentName +- (void)schedulerOptimisticallyCreateComponentViewWithComponentHandle:(ComponentHandle)componentHandle { - [_mountingManager preliminaryCreateComponentViewWithName:componentName]; + [_mountingManager optimisticallyCreateComponentViewWithComponentHandle:componentHandle]; } #pragma mark - RCTMountingManagerDelegate