mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Fabric: Implementation of RCTMountingTransactionObserving protocol
Summary: This diff finally uses all facilities from the previous diffs to build an implementation of `RCTMountingTransactionObserving` protocol which does *not* require using expensive Objective-C runtime features. In the coming diffs, we will see how it can/should be used. Changelog: [Internal] Fabric-specific internal change. Reviewed By: sammy-SC Differential Revision: D18217101 fbshipit-source-id: 34f411dcb527dc81570c2f2833ce13b40e1450db
This commit is contained in:
committed by
Facebook Github Bot
parent
20a0f224ba
commit
41cf6da074
@@ -20,6 +20,13 @@ class RCTComponentViewClassDescriptor final {
|
||||
* Associated (and owned) native view class.
|
||||
*/
|
||||
Class<RCTComponentViewProtocol> viewClass;
|
||||
|
||||
/*
|
||||
* Indicates a requirement to call on the view methods from
|
||||
* `RCTMountingTransactionObserving` protocol.
|
||||
*/
|
||||
bool observesMountingTransactionWillMount{false};
|
||||
bool observesMountingTransactionDidMount{false};
|
||||
};
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -22,6 +22,31 @@ class RCTComponentViewDescriptor final {
|
||||
* Associated (and owned) native view instance.
|
||||
*/
|
||||
UIView<RCTComponentViewProtocol> *view;
|
||||
|
||||
/*
|
||||
* Indicates a requirement to call on the view methods from
|
||||
* `RCTMountingTransactionObserving` protocol.
|
||||
*/
|
||||
bool observesMountingTransactionWillMount{false};
|
||||
bool observesMountingTransactionDidMount{false};
|
||||
};
|
||||
|
||||
inline bool operator==(RCTComponentViewDescriptor const &lhs, RCTComponentViewDescriptor const &rhs)
|
||||
{
|
||||
return lhs.view == rhs.view;
|
||||
}
|
||||
|
||||
inline bool operator!=(RCTComponentViewDescriptor const &lhs, RCTComponentViewDescriptor const &rhs)
|
||||
{
|
||||
return lhs.view != rhs.view;
|
||||
}
|
||||
|
||||
template <>
|
||||
struct std::hash<RCTComponentViewDescriptor> {
|
||||
size_t operator()(RCTComponentViewDescriptor const &componentViewDescriptor) const
|
||||
{
|
||||
return std::hash<void *>()((__bridge void *)componentViewDescriptor.view);
|
||||
}
|
||||
};
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#import <React/RCTAssert.h>
|
||||
#import <React/RCTConversions.h>
|
||||
|
||||
#import <better/map.h>
|
||||
#import <better/mutex.h>
|
||||
|
||||
@@ -21,6 +22,7 @@
|
||||
#import "RCTImageComponentView.h"
|
||||
#import "RCTLegacyViewManagerInteropComponentView.h"
|
||||
#import "RCTModalHostViewComponentView.h"
|
||||
#import "RCTMountingTransactionObserving.h"
|
||||
#import "RCTParagraphComponentView.h"
|
||||
#import "RCTPullToRefreshViewComponentView.h"
|
||||
#import "RCTRootComponentView.h"
|
||||
@@ -31,6 +33,8 @@
|
||||
#import "RCTUnimplementedNativeComponentView.h"
|
||||
#import "RCTViewComponentView.h"
|
||||
|
||||
#import <objc/runtime.h>
|
||||
|
||||
using namespace facebook::react;
|
||||
|
||||
@implementation RCTComponentViewFactory {
|
||||
@@ -79,7 +83,17 @@ using namespace facebook::react;
|
||||
|
||||
- (RCTComponentViewClassDescriptor)_componentViewClassDescriptorFromClass:(Class<RCTComponentViewProtocol>)viewClass
|
||||
{
|
||||
return RCTComponentViewClassDescriptor{.viewClass = viewClass};
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wundeclared-selector"
|
||||
return RCTComponentViewClassDescriptor
|
||||
{
|
||||
.viewClass = viewClass,
|
||||
.observesMountingTransactionWillMount =
|
||||
(bool)class_respondsToSelector(viewClass, @selector(mountingTransactionWillMountWithMetadata:)),
|
||||
.observesMountingTransactionDidMount =
|
||||
(bool)class_respondsToSelector(viewClass, @selector(mountingTransactionDidMountWithMetadata:)),
|
||||
};
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
- (void)registerComponentViewClass:(Class<RCTComponentViewProtocol>)componentViewClass
|
||||
@@ -120,7 +134,11 @@ using namespace facebook::react;
|
||||
auto componentViewClassDescriptor = iterator->second;
|
||||
Class viewClass = componentViewClassDescriptor.viewClass;
|
||||
|
||||
return RCTComponentViewDescriptor{.view = [[viewClass alloc] init]};
|
||||
return RCTComponentViewDescriptor{
|
||||
.view = [[viewClass alloc] init],
|
||||
.observesMountingTransactionWillMount = componentViewClassDescriptor.observesMountingTransactionWillMount,
|
||||
.observesMountingTransactionDidMount = componentViewClassDescriptor.observesMountingTransactionDidMount,
|
||||
};
|
||||
}
|
||||
|
||||
- (facebook::react::ComponentDescriptorRegistry::Shared)createComponentDescriptorRegistryWithParameters:
|
||||
|
||||
@@ -77,6 +77,8 @@ const NSInteger RCTComponentViewRegistryRecyclePoolMaxSize = 1024;
|
||||
@implementation RCTComponentViewRegistry {
|
||||
better::map<Tag, RCTComponentViewDescriptor> _registry;
|
||||
better::map<ComponentHandle, std::vector<RCTComponentViewDescriptor>> _recyclePool;
|
||||
|
||||
std::unordered_set<RCTComponentViewDescriptor> _mountingTransactionObservers;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
@@ -133,6 +135,11 @@ const NSInteger RCTComponentViewRegistryRecyclePoolMaxSize = 1024;
|
||||
|
||||
_registry.insert({tag, componentViewDescriptor});
|
||||
|
||||
if (componentViewDescriptor.observesMountingTransactionDidMount ||
|
||||
componentViewDescriptor.observesMountingTransactionWillMount) {
|
||||
_mountingTransactionObservers.insert(componentViewDescriptor);
|
||||
}
|
||||
|
||||
#ifdef LEGACY_UIMANAGER_INTEGRATION_ENABLED
|
||||
[RCTUIManager registerView:componentViewDescriptor.view];
|
||||
#endif
|
||||
@@ -153,6 +160,11 @@ const NSInteger RCTComponentViewRegistryRecyclePoolMaxSize = 1024;
|
||||
[RCTUIManager unregisterView:componentViewDescriptor.view];
|
||||
#endif
|
||||
|
||||
if (componentViewDescriptor.observesMountingTransactionDidMount ||
|
||||
componentViewDescriptor.observesMountingTransactionWillMount) {
|
||||
_mountingTransactionObservers.erase(componentViewDescriptor);
|
||||
}
|
||||
|
||||
_registry.erase(tag);
|
||||
componentViewDescriptor.view.tag = 0;
|
||||
[self _enqueueComponentViewWithComponentHandle:componentHandle componentViewDescriptor:componentViewDescriptor];
|
||||
|
||||
@@ -19,22 +19,35 @@
|
||||
#import "RCTComponentViewProtocol.h"
|
||||
#import "RCTComponentViewRegistry.h"
|
||||
#import "RCTConversions.h"
|
||||
#import "RCTMountingTransactionObserverCoordinator.h"
|
||||
|
||||
using namespace facebook;
|
||||
using namespace facebook::react;
|
||||
|
||||
// `Create` instruction
|
||||
static void RNCreateMountInstruction(ShadowViewMutation const &mutation, RCTComponentViewRegistry *registry)
|
||||
static void RNCreateMountInstruction(
|
||||
ShadowViewMutation const &mutation,
|
||||
RCTComponentViewRegistry *registry,
|
||||
RCTMountingTransactionObserverCoordinator &observerCoordinator,
|
||||
SurfaceId surfaceId)
|
||||
{
|
||||
[registry dequeueComponentViewWithComponentHandle:mutation.newChildShadowView.componentHandle
|
||||
tag:mutation.newChildShadowView.tag];
|
||||
auto componentViewDescriptor =
|
||||
[registry dequeueComponentViewWithComponentHandle:mutation.newChildShadowView.componentHandle
|
||||
tag:mutation.newChildShadowView.tag];
|
||||
|
||||
observerCoordinator.registerViewComponentDescriptor(componentViewDescriptor, surfaceId);
|
||||
}
|
||||
|
||||
// `Delete` instruction
|
||||
static void RNDeleteMountInstruction(ShadowViewMutation const &mutation, RCTComponentViewRegistry *registry)
|
||||
static void RNDeleteMountInstruction(
|
||||
ShadowViewMutation const &mutation,
|
||||
RCTComponentViewRegistry *registry,
|
||||
RCTMountingTransactionObserverCoordinator &observerCoordinator,
|
||||
SurfaceId surfaceId)
|
||||
{
|
||||
auto const &oldChildShadowView = mutation.oldChildShadowView;
|
||||
RCTComponentViewDescriptor componentViewDescriptor = [registry componentViewDescriptorWithTag:oldChildShadowView.tag];
|
||||
observerCoordinator.unregisterViewComponentDescriptor(componentViewDescriptor, surfaceId);
|
||||
[registry enqueueComponentViewWithComponentHandle:oldChildShadowView.componentHandle
|
||||
tag:oldChildShadowView.tag
|
||||
componentViewDescriptor:componentViewDescriptor];
|
||||
@@ -123,18 +136,22 @@ static void RNFinalizeUpdatesMountInstruction(
|
||||
}
|
||||
|
||||
// `Update` instruction
|
||||
static void RNPerformMountInstructions(ShadowViewMutationList const &mutations, RCTComponentViewRegistry *registry)
|
||||
static void RNPerformMountInstructions(
|
||||
ShadowViewMutationList const &mutations,
|
||||
RCTComponentViewRegistry *registry,
|
||||
RCTMountingTransactionObserverCoordinator &observerCoordinator,
|
||||
SurfaceId surfaceId)
|
||||
{
|
||||
SystraceSection s("RNPerformMountInstructions");
|
||||
|
||||
for (auto const &mutation : mutations) {
|
||||
switch (mutation.type) {
|
||||
case ShadowViewMutation::Create: {
|
||||
RNCreateMountInstruction(mutation, registry);
|
||||
RNCreateMountInstruction(mutation, registry, observerCoordinator, surfaceId);
|
||||
break;
|
||||
}
|
||||
case ShadowViewMutation::Delete: {
|
||||
RNDeleteMountInstruction(mutation, registry);
|
||||
RNDeleteMountInstruction(mutation, registry, observerCoordinator, surfaceId);
|
||||
break;
|
||||
}
|
||||
case ShadowViewMutation::Insert: {
|
||||
@@ -188,7 +205,9 @@ static void RNPerformMountInstructions(ShadowViewMutationList const &mutations,
|
||||
}
|
||||
}
|
||||
|
||||
@implementation RCTMountingManager
|
||||
@implementation RCTMountingManager {
|
||||
RCTMountingTransactionObserverCoordinator _observerCoordinator;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
@@ -250,8 +269,12 @@ static void RNPerformMountInstructions(ShadowViewMutationList const &mutations,
|
||||
}
|
||||
|
||||
RCTAssertMainQueue();
|
||||
auto metadata = MountingTransactionMetadata{surfaceId, transaction->getNumber(), transaction->getTelemetry()};
|
||||
|
||||
[self.delegate mountingManager:self willMountComponentsWithRootTag:surfaceId];
|
||||
RNPerformMountInstructions(mutations, self.componentViewRegistry);
|
||||
_observerCoordinator.notifyObserversMountingTransactionWillMount(metadata);
|
||||
RNPerformMountInstructions(mutations, self.componentViewRegistry, _observerCoordinator, surfaceId);
|
||||
_observerCoordinator.notifyObserversMountingTransactionDidMount(metadata);
|
||||
[self.delegate mountingManager:self didMountComponentsWithRootTag:surfaceId];
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 <React/RCTComponentViewDescriptor.h>
|
||||
#import "RCTMountingTransactionObserverCoordinator.h"
|
||||
|
||||
#import <better/map.h>
|
||||
#import <better/set.h>
|
||||
|
||||
#import <react/mounting/MountingTransactionMetadata.h>
|
||||
|
||||
class RCTMountingTransactionObserverCoordinator final {
|
||||
public:
|
||||
/*
|
||||
* Registers (and unregisters) specified `componentViewDescriptor` in the registry of views that need to be notified.
|
||||
* Does nothing if a particular `componentViewDescriptor` does not listen the events.
|
||||
*/
|
||||
void registerViewComponentDescriptor(
|
||||
RCTComponentViewDescriptor const &componentViewDescriptor,
|
||||
facebook::react::SurfaceId surfaceId);
|
||||
void unregisterViewComponentDescriptor(
|
||||
RCTComponentViewDescriptor const &componentViewDescriptor,
|
||||
facebook::react::SurfaceId surfaceId);
|
||||
|
||||
/*
|
||||
* To be called from `RCTMountingManager`.
|
||||
*/
|
||||
void notifyObserversMountingTransactionWillMount(
|
||||
facebook::react::MountingTransactionMetadata const &metadata) const;
|
||||
void notifyObserversMountingTransactionDidMount(
|
||||
facebook::react::MountingTransactionMetadata const &metadata) const;
|
||||
|
||||
private:
|
||||
facebook::better::map<
|
||||
facebook::react::SurfaceId,
|
||||
facebook::better::set<RCTComponentViewDescriptor>>
|
||||
registry_;
|
||||
};
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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 "RCTMountingTransactionObserverCoordinator.h"
|
||||
|
||||
#import "RCTMountingTransactionObserving.h"
|
||||
|
||||
using namespace facebook::react;
|
||||
|
||||
void RCTMountingTransactionObserverCoordinator::registerViewComponentDescriptor(
|
||||
RCTComponentViewDescriptor const &componentViewDescriptor,
|
||||
SurfaceId surfaceId)
|
||||
{
|
||||
if (!componentViewDescriptor.observesMountingTransactionWillMount &&
|
||||
!componentViewDescriptor.observesMountingTransactionDidMount) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto &surfaceRegistry = registry_[surfaceId];
|
||||
surfaceRegistry.insert(componentViewDescriptor);
|
||||
}
|
||||
|
||||
void RCTMountingTransactionObserverCoordinator::unregisterViewComponentDescriptor(
|
||||
RCTComponentViewDescriptor const &componentViewDescriptor,
|
||||
SurfaceId surfaceId)
|
||||
{
|
||||
if (!componentViewDescriptor.observesMountingTransactionWillMount &&
|
||||
!componentViewDescriptor.observesMountingTransactionDidMount) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto &surfaceRegistry = registry_[surfaceId];
|
||||
surfaceRegistry.erase(componentViewDescriptor);
|
||||
}
|
||||
|
||||
void RCTMountingTransactionObserverCoordinator::notifyObserversMountingTransactionWillMount(
|
||||
MountingTransactionMetadata const &metadata) const
|
||||
{
|
||||
auto surfaceId = metadata.surfaceId;
|
||||
auto surfaceRegistryIterator = registry_.find(surfaceId);
|
||||
if (surfaceRegistryIterator == registry_.end()) {
|
||||
return;
|
||||
}
|
||||
auto &surfaceRegistry = surfaceRegistryIterator->second;
|
||||
for (auto const &componentViewDescriptor : surfaceRegistry) {
|
||||
if (componentViewDescriptor.observesMountingTransactionWillMount) {
|
||||
[(id<RCTMountingTransactionObserving>)componentViewDescriptor.view
|
||||
mountingTransactionWillMountWithMetadata:metadata];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RCTMountingTransactionObserverCoordinator::notifyObserversMountingTransactionDidMount(
|
||||
MountingTransactionMetadata const &metadata) const
|
||||
{
|
||||
auto surfaceId = metadata.surfaceId;
|
||||
auto surfaceRegistryIterator = registry_.find(surfaceId);
|
||||
if (surfaceRegistryIterator == registry_.end()) {
|
||||
return;
|
||||
}
|
||||
auto &surfaceRegistry = surfaceRegistryIterator->second;
|
||||
for (auto const &componentViewDescriptor : surfaceRegistry) {
|
||||
if (componentViewDescriptor.observesMountingTransactionDidMount) {
|
||||
[(id<RCTMountingTransactionObserving>)componentViewDescriptor.view
|
||||
mountingTransactionDidMountWithMetadata:metadata];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ namespace react {
|
||||
/*
|
||||
* Contains all (meta)information related to a MountingTransaction except a list
|
||||
* of mutation instructions.
|
||||
* The class is meant to be used when a cosumer should not have access to all
|
||||
* The class is meant to be used when a consumer should not have access to all
|
||||
* information about the transaction (incapsulation) but still needs to observe
|
||||
* it to produce some side-effects.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user