Skip to content

Commit

Permalink
Introducing RCTComponentViewFactory
Browse files Browse the repository at this point in the history
Summary:
The whole mounting iOS infra now uses `ComponentHandle` instead of `std::string` as a reference to particular `ComponentView` implementation. All changes are pretty straightforward, we use a different thing/type to refer to the particular class; no changes in the logic besides a new `RCTComponentViewFactory` that serves the same role of classes registry as Objective-C runtime served previously.
That has several benefits:
* It should be slightly faster, mostly because we don't need to convert `char *` strings to `std::string` and then to `NSString *`.
* We don't need string-based component-name maps anymore (at least on this layer). We can call classes as we want and it will work because of classes are now explicit about which ShadowNodes they are compatible with.
* Most importantly, it's explicit now! That means that no runtime magic is involved anymore and we can rely on static linting tool now and not be afraid of improper code stripping/overoptimization.

Reviewed By: mdvacca

Differential Revision: D13130760

fbshipit-source-id: aadf70525a1335b96992443abae4da359efdc829
  • Loading branch information
shergin authored and facebook-github-bot committed Nov 26, 2018
1 parent eef3df8 commit e581977
Show file tree
Hide file tree
Showing 14 changed files with 186 additions and 66 deletions.
5 changes: 3 additions & 2 deletions React/Fabric/Mounting/MountItems/RCTCreateMountItem.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#import <UIKit/UIKit.h>

#import <react/core/ReactPrimitives.h>
#import <React/RCTMountItemProtocol.h>
#import <React/RCTPrimitives.h>

Expand All @@ -19,8 +20,8 @@ NS_ASSUME_NONNULL_BEGIN
*/
@interface RCTCreateMountItem : NSObject <RCTMountItemProtocol>

- (instancetype)initWithComponentName:(NSString *)componentName
tag:(ReactTag)tag;
- (instancetype)initWithComponentHandle:(facebook::react::ComponentHandle)componentHandle
tag:(ReactTag)tag;

@end

Expand Down
12 changes: 7 additions & 5 deletions React/Fabric/Mounting/MountItems/RCTCreateMountItem.mm
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -27,7 +29,7 @@ - (instancetype)initWithComponentName:(NSString *)componentName

- (void)executeWithRegistry:(RCTComponentViewRegistry *)registry
{
[registry dequeueComponentViewWithName:_componentName tag:_tag];
[registry dequeueComponentViewWithComponentHandle:_componentHandle tag:_tag];
}

@end
5 changes: 3 additions & 2 deletions React/Fabric/Mounting/MountItems/RCTDeleteMountItem.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#import <UIKit/UIKit.h>

#import <react/core/ReactPrimitives.h>
#import <React/RCTMountItemProtocol.h>
#import <React/RCTPrimitives.h>

Expand All @@ -17,8 +18,8 @@ NS_ASSUME_NONNULL_BEGIN
*/
@interface RCTDeleteMountItem : NSObject <RCTMountItemProtocol>

- (instancetype)initWithComponentName:(NSString *)componentName
tag:(ReactTag)tag;
- (instancetype)initWithComponentHandle:(facebook::react::ComponentHandle)componentHandle
tag:(ReactTag)tag;

@end

Expand Down
12 changes: 7 additions & 5 deletions React/Fabric/Mounting/MountItems/RCTDeleteMountItem.mm
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -33,7 +35,7 @@ - (void)executeWithRegistry:(RCTComponentViewRegistry *)registry
return;
}

[registry enqueueComponentViewWithName:_componentName tag:_tag componentView:componentView];
[registry enqueueComponentViewWithComponentHandle:_componentHandle tag:_tag componentView:componentView];
}

@end
37 changes: 37 additions & 0 deletions React/Fabric/Mounting/RCTComponentViewFactory.h
Original file line number Diff line number Diff line change
@@ -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 <UIKit/UIKit.h>

#import <React/RCTComponentViewProtocol.h>

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<RCTComponentViewProtocol>)componentViewClass;

/**
* Creates a component view with given component handle.
*/
- (UIView<RCTComponentViewProtocol> *)createComponentViewWithComponentHandle:(facebook::react::ComponentHandle)componentHandle;

@end

NS_ASSUME_NONNULL_END
65 changes: 65 additions & 0 deletions React/Fabric/Mounting/RCTComponentViewFactory.mm
Original file line number Diff line number Diff line change
@@ -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 <React/RCTAssert.h>
#import <react/core/ReactPrimitives.h>

#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<ComponentHandle, Class<RCTComponentViewProtocol>> _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<RCTComponentViewProtocol>)componentViewClass
{
RCTAssertMainQueue();

ComponentHandle componentHandle = [componentViewClass componentHandle];
_registry[componentHandle] = componentViewClass;
}

- (UIView<RCTComponentViewProtocol> *)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
18 changes: 11 additions & 7 deletions React/Fabric/Mounting/RCTComponentViewRegistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

#import <UIKit/UIKit.h>

#import <react/core/ReactPrimitives.h>
#import <React/RCTComponentViewFactory.h>
#import <React/RCTComponentViewProtocol.h>

NS_ASSUME_NONNULL_BEGIN
Expand All @@ -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<RCTComponentViewProtocol> *)dequeueComponentViewWithName:(NSString *)componentName
tag:(ReactTag)tag;
- (UIView<RCTComponentViewProtocol> *)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<RCTComponentViewProtocol> *)componentView;
- (void)enqueueComponentViewWithComponentHandle:(facebook::react::ComponentHandle)componentHandle
tag:(ReactTag)tag
componentView:(UIView<RCTComponentViewProtocol> *)componentView;

/**
* Returns a native component view by given `tag`.
Expand All @@ -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

Expand Down
54 changes: 25 additions & 29 deletions React/Fabric/Mounting/RCTComponentViewRegistry.mm
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#import <Foundation/NSMapTable.h>
#import <React/RCTAssert.h>

using namespace facebook::react;

#define LEGACY_UIMANAGER_INTEGRATION_ENABLED 1

#ifdef LEGACY_UIMANAGER_INTEGRATION_ENABLED
Expand Down Expand Up @@ -67,32 +69,33 @@ + (void)unregisterView:(UIView *)view
const NSInteger RCTComponentViewRegistryRecyclePoolMaxSize = 1024;

@implementation RCTComponentViewRegistry {
NSMapTable<id, UIView<RCTComponentViewProtocol> *> *_registry;
NSMapTable<NSString *, NSHashTable<UIView<RCTComponentViewProtocol> *> *> *_recyclePool;
NSMapTable<id /* ReactTag */, UIView<RCTComponentViewProtocol> *> *_registry;
NSMapTable<id /* ComponentHandle */, NSHashTable<UIView<RCTComponentViewProtocol> *> *> *_recyclePool;
}

- (instancetype)init
{
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<RCTComponentViewProtocol> *)dequeueComponentViewWithName:(NSString *)componentName
tag:(ReactTag)tag
- (UIView<RCTComponentViewProtocol> *)dequeueComponentViewWithComponentHandle:(ComponentHandle)componentHandle
tag:(ReactTag)tag
{
RCTAssertMainQueue();

RCTAssert(![_registry objectForKey:(__bridge id)(void *)tag],
@"RCTComponentViewRegistry: Attempt to dequeue already registered component.");

UIView<RCTComponentViewProtocol> *componentView =
[self _dequeueComponentViewWithName:componentName];
[self _dequeueComponentViewWithComponentHandle:componentHandle];
componentView.tag = tag;
[_registry setObject:componentView forKey:(__bridge id)(void *)tag];

Expand All @@ -103,9 +106,9 @@ - (instancetype)init
return componentView;
}

- (void)enqueueComponentViewWithName:(NSString *)componentName
tag:(ReactTag)tag
componentView:(UIView<RCTComponentViewProtocol> *)componentView
- (void)enqueueComponentViewWithComponentHandle:(ComponentHandle)componentHandle
tag:(ReactTag)tag
componentView:(UIView<RCTComponentViewProtocol> *)componentView
{
RCTAssertMainQueue();

Expand All @@ -118,14 +121,14 @@ - (void)enqueueComponentViewWithName:(NSString *)componentName

[_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<RCTComponentViewProtocol> *)componentViewByTag:(ReactTag)tag
Expand All @@ -140,38 +143,31 @@ - (ReactTag)tagByComponentView:(UIView<RCTComponentViewProtocol> *)componentView
return componentView.tag;
}

- (UIView<RCTComponentViewProtocol> *)_createComponentViewWithName:(NSString *)componentName
{
RCTAssertMainQueue();
// This is temporary approach.
NSString *className = [NSString stringWithFormat:@"RCT%@ComponentView", componentName];
UIView<RCTComponentViewProtocol> *componentView = [[NSClassFromString(className) alloc] init];
return componentView;
}

- (nullable UIView<RCTComponentViewProtocol> *)_dequeueComponentViewWithName:(NSString *)componentName
- (nullable UIView<RCTComponentViewProtocol> *)_dequeueComponentViewWithComponentHandle:(ComponentHandle)componentHandle
{
RCTAssertMainQueue();
NSHashTable<UIView<RCTComponentViewProtocol> *> *componentViews = [_recyclePool objectForKey:componentName];
NSHashTable<UIView<RCTComponentViewProtocol> *> *componentViews =
[_recyclePool objectForKey:(__bridge id)(void *)componentHandle];
if (!componentViews || componentViews.count == 0) {
return [self _createComponentViewWithName:componentName];
return [self.componentViewFactory createComponentViewWithComponentHandle:componentHandle];
}

UIView<RCTComponentViewProtocol> *componentView = [componentViews anyObject];
[componentViews removeObject:componentView];
return componentView;
}

- (void)_enqueueComponentViewWithName:(NSString *)componentName
componentView:(UIView<RCTComponentViewProtocol> *)componentView
- (void)_enqueueComponentViewWithComponentHandle:(ComponentHandle)componentHandle
componentView:(UIView<RCTComponentViewProtocol> *)componentView
{
RCTAssertMainQueue();
[componentView prepareForRecycle];

NSHashTable<UIView<RCTComponentViewProtocol> *> *componentViews = [_recyclePool objectForKey:componentName];
NSHashTable<UIView<RCTComponentViewProtocol> *> *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) {
Expand Down
3 changes: 2 additions & 1 deletion React/Fabric/Mounting/RCTMountingManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#import <UIKit/UIKit.h>

#import <react/core/ReactPrimitives.h>
#import <react/uimanager/ShadowView.h>
#import <react/uimanager/ShadowViewMutation.h>
#import <React/RCTPrimitives.h>
Expand Down Expand Up @@ -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

Expand Down
Loading

0 comments on commit e581977

Please sign in to comment.