Fabric: Using `PlatformRunLoopObserver` instead of `MainRunLoopEventBeat` and `RuntimeEventBeat` on iOS (gated)
Summary: This diff implements iOS-specific `PlatformRunLoopObserver` (and `MainRunLoopObserver`) that then being glued together with `SynchronousEventBeat` replaces `MainRunLoopEventBeat`, and then same thing glued with `AsynchronousEventBeat` replaces `RuntimeEventBeat`. So, instead of two platform-specific classes we had on iOS (for that needs), now we have only one (that can be reused for a more broad variety of applications). Changelog: [Internal] Fabric-specific internal change. Reviewed By: sammy-SC Differential Revision: D21341998 fbshipit-source-id: fafde4e678770f7fcf9c1ff87acc02812a37e708
This commit is contained in:
Родитель
ebdd59aff8
Коммит
f05fff6a68
|
@ -28,11 +28,14 @@
|
||||||
#import <react/config/ReactNativeConfig.h>
|
#import <react/config/ReactNativeConfig.h>
|
||||||
#import <react/core/LayoutConstraints.h>
|
#import <react/core/LayoutConstraints.h>
|
||||||
#import <react/core/LayoutContext.h>
|
#import <react/core/LayoutContext.h>
|
||||||
|
#import <react/scheduler/AsynchronousEventBeat.h>
|
||||||
#import <react/scheduler/SchedulerToolbox.h>
|
#import <react/scheduler/SchedulerToolbox.h>
|
||||||
|
#import <react/scheduler/SynchronousEventBeat.h>
|
||||||
#import <react/utils/ContextContainer.h>
|
#import <react/utils/ContextContainer.h>
|
||||||
#import <react/utils/ManagedObjectWrapper.h>
|
#import <react/utils/ManagedObjectWrapper.h>
|
||||||
|
|
||||||
#import "MainRunLoopEventBeat.h"
|
#import "MainRunLoopEventBeat.h"
|
||||||
|
#import "PlatformRunLoopObserver.h"
|
||||||
#import "RCTConversions.h"
|
#import "RCTConversions.h"
|
||||||
#import "RuntimeEventBeat.h"
|
#import "RuntimeEventBeat.h"
|
||||||
|
|
||||||
|
@ -275,6 +278,8 @@ static inline LayoutContext RCTGetLayoutContext()
|
||||||
|
|
||||||
- (RCTScheduler *)_createScheduler
|
- (RCTScheduler *)_createScheduler
|
||||||
{
|
{
|
||||||
|
auto reactNativeConfig = _contextContainer->at<std::shared_ptr<ReactNativeConfig const>>("ReactNativeConfig");
|
||||||
|
|
||||||
auto componentRegistryFactory =
|
auto componentRegistryFactory =
|
||||||
[factory = wrapManagedObject(_mountingManager.componentViewRegistry.componentViewFactory)](
|
[factory = wrapManagedObject(_mountingManager.componentViewRegistry.componentViewFactory)](
|
||||||
EventDispatcher::Weak const &eventDispatcher, ContextContainer::Shared const &contextContainer) {
|
EventDispatcher::Weak const &eventDispatcher, ContextContainer::Shared const &contextContainer) {
|
||||||
|
@ -288,19 +293,36 @@ static inline LayoutContext RCTGetLayoutContext()
|
||||||
toolbox.contextContainer = _contextContainer;
|
toolbox.contextContainer = _contextContainer;
|
||||||
toolbox.componentRegistryFactory = componentRegistryFactory;
|
toolbox.componentRegistryFactory = componentRegistryFactory;
|
||||||
toolbox.runtimeExecutor = runtimeExecutor;
|
toolbox.runtimeExecutor = runtimeExecutor;
|
||||||
|
toolbox.mainRunLoopObserverFactory = [](RunLoopObserver::Activity activities,
|
||||||
toolbox.synchronousEventBeatFactory = [runtimeExecutor](EventBeat::SharedOwnerBox const &ownerBox) {
|
RunLoopObserver::WeakOwner const &owner) {
|
||||||
return std::make_unique<MainRunLoopEventBeat>(ownerBox, runtimeExecutor);
|
return std::make_unique<MainRunLoopObserver>(activities, owner);
|
||||||
};
|
};
|
||||||
|
|
||||||
toolbox.asynchronousEventBeatFactory = [runtimeExecutor](EventBeat::SharedOwnerBox const &ownerBox) {
|
if (reactNativeConfig && reactNativeConfig->getBool("react_fabric:enable_run_loop_based_event_beat_ios")) {
|
||||||
return std::make_unique<RuntimeEventBeat>(ownerBox, runtimeExecutor);
|
toolbox.synchronousEventBeatFactory = [runtimeExecutor](EventBeat::SharedOwnerBox const &ownerBox) {
|
||||||
};
|
auto runLoopObserver =
|
||||||
|
std::make_unique<MainRunLoopObserver const>(RunLoopObserver::Activity::BeforeWaiting, ownerBox->owner);
|
||||||
|
return std::make_unique<SynchronousEventBeat>(std::move(runLoopObserver), runtimeExecutor);
|
||||||
|
};
|
||||||
|
|
||||||
|
toolbox.asynchronousEventBeatFactory = [runtimeExecutor](EventBeat::SharedOwnerBox const &ownerBox) {
|
||||||
|
auto runLoopObserver =
|
||||||
|
std::make_unique<MainRunLoopObserver const>(RunLoopObserver::Activity::BeforeWaiting, ownerBox->owner);
|
||||||
|
return std::make_unique<AsynchronousEventBeat>(std::move(runLoopObserver), runtimeExecutor);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
toolbox.synchronousEventBeatFactory = [runtimeExecutor](EventBeat::SharedOwnerBox const &ownerBox) {
|
||||||
|
return std::make_unique<MainRunLoopEventBeat>(ownerBox, runtimeExecutor);
|
||||||
|
};
|
||||||
|
|
||||||
|
toolbox.asynchronousEventBeatFactory = [runtimeExecutor](EventBeat::SharedOwnerBox const &ownerBox) {
|
||||||
|
return std::make_unique<RuntimeEventBeat>(ownerBox, runtimeExecutor);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
RCTScheduler *scheduler = [[RCTScheduler alloc] initWithToolbox:toolbox];
|
RCTScheduler *scheduler = [[RCTScheduler alloc] initWithToolbox:toolbox];
|
||||||
scheduler.delegate = self;
|
scheduler.delegate = self;
|
||||||
|
|
||||||
auto reactNativeConfig = _contextContainer->at<std::shared_ptr<ReactNativeConfig const>>("ReactNativeConfig");
|
|
||||||
if (reactNativeConfig) {
|
if (reactNativeConfig) {
|
||||||
_mountingManager.useModernDifferentiatorMode =
|
_mountingManager.useModernDifferentiatorMode =
|
||||||
reactNativeConfig->getBool("react_fabric:enabled_optimized_moves_differ_ios");
|
reactNativeConfig->getBool("react_fabric:enabled_optimized_moves_differ_ios");
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <CoreFoundation/CFRunLoop.h>
|
||||||
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
|
||||||
|
#include <react/utils/RunLoopObserver.h>
|
||||||
|
|
||||||
|
namespace facebook {
|
||||||
|
namespace react {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Concrete iOS-specific implementation of `RunLoopObserver` using
|
||||||
|
* `CFRunLoopObserver` under the hood.
|
||||||
|
*/
|
||||||
|
class PlatformRunLoopObserver : public RunLoopObserver {
|
||||||
|
public:
|
||||||
|
PlatformRunLoopObserver(
|
||||||
|
RunLoopObserver::Activity activities,
|
||||||
|
RunLoopObserver::WeakOwner const &owner,
|
||||||
|
CFRunLoopRef runLoop);
|
||||||
|
|
||||||
|
~PlatformRunLoopObserver();
|
||||||
|
|
||||||
|
virtual bool isOnRunLoopThread() const noexcept override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void startObserving() const noexcept override;
|
||||||
|
void stopObserving() const noexcept override;
|
||||||
|
|
||||||
|
CFRunLoopRef runLoop_;
|
||||||
|
CFRunLoopObserverRef mainRunLoopObserver_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convenience specialization of `PlatformRunLoopObserver` observing the main
|
||||||
|
* run loop.
|
||||||
|
*/
|
||||||
|
class MainRunLoopObserver final : public PlatformRunLoopObserver {
|
||||||
|
public:
|
||||||
|
MainRunLoopObserver(
|
||||||
|
RunLoopObserver::Activity activities,
|
||||||
|
RunLoopObserver::WeakOwner const &owner)
|
||||||
|
: PlatformRunLoopObserver(activities, owner, CFRunLoopGetMain()) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace react
|
||||||
|
} // namespace facebook
|
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* 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 "PlatformRunLoopObserver.h"
|
||||||
|
|
||||||
|
#import <mutex>
|
||||||
|
|
||||||
|
namespace facebook {
|
||||||
|
namespace react {
|
||||||
|
|
||||||
|
static CFRunLoopActivity toCFRunLoopActivity(RunLoopObserver::Activity activity)
|
||||||
|
{
|
||||||
|
auto result = CFRunLoopActivity{};
|
||||||
|
|
||||||
|
if (RunLoopObserver::Activity(activity & RunLoopObserver::Activity::BeforeWaiting) ==
|
||||||
|
RunLoopObserver::Activity::BeforeWaiting) {
|
||||||
|
result = result | kCFRunLoopBeforeWaiting;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RunLoopObserver::Activity(activity & RunLoopObserver::Activity::AfterWaiting) ==
|
||||||
|
RunLoopObserver::Activity::AfterWaiting) {
|
||||||
|
result = result | kCFRunLoopAfterWaiting;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static RunLoopObserver::Activity toRunLoopActivity(CFRunLoopActivity activity)
|
||||||
|
{
|
||||||
|
auto result = RunLoopObserver::Activity{};
|
||||||
|
|
||||||
|
if (CFRunLoopActivity(activity & kCFRunLoopBeforeWaiting) == kCFRunLoopBeforeWaiting) {
|
||||||
|
result = RunLoopObserver::Activity(result | RunLoopObserver::Activity::BeforeWaiting);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CFRunLoopActivity(activity & kCFRunLoopAfterWaiting) == kCFRunLoopAfterWaiting) {
|
||||||
|
result = RunLoopObserver::Activity(result | RunLoopObserver::Activity::AfterWaiting);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlatformRunLoopObserver::PlatformRunLoopObserver(
|
||||||
|
RunLoopObserver::Activity activities,
|
||||||
|
RunLoopObserver::WeakOwner const &owner,
|
||||||
|
CFRunLoopRef runLoop)
|
||||||
|
: RunLoopObserver(activities, owner), runLoop_(runLoop)
|
||||||
|
{
|
||||||
|
// A value (not a reference) to be captured by the block.
|
||||||
|
auto weakOwner = owner;
|
||||||
|
|
||||||
|
// The documentation for `CFRunLoop` family API states that all of the methods are thread-safe.
|
||||||
|
// See "Thread Safety and Run Loop Objects" section of the "Threading Programming Guide" for more details.
|
||||||
|
mainRunLoopObserver_ = CFRunLoopObserverCreateWithHandler(
|
||||||
|
NULL /* allocator */,
|
||||||
|
toCFRunLoopActivity(activities_) /* activities */,
|
||||||
|
true /* repeats */,
|
||||||
|
0 /* order */,
|
||||||
|
^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
|
||||||
|
auto strongOwner = weakOwner.lock();
|
||||||
|
if (!strongOwner) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->activityDidChange(toRunLoopActivity(activity));
|
||||||
|
});
|
||||||
|
|
||||||
|
assert(mainRunLoopObserver_);
|
||||||
|
}
|
||||||
|
|
||||||
|
PlatformRunLoopObserver::~PlatformRunLoopObserver()
|
||||||
|
{
|
||||||
|
stopObserving();
|
||||||
|
CFRelease(mainRunLoopObserver_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformRunLoopObserver::startObserving() const noexcept
|
||||||
|
{
|
||||||
|
CFRunLoopAddObserver(runLoop_, mainRunLoopObserver_, kCFRunLoopCommonModes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformRunLoopObserver::stopObserving() const noexcept
|
||||||
|
{
|
||||||
|
CFRunLoopRemoveObserver(runLoop_, mainRunLoopObserver_, kCFRunLoopCommonModes);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PlatformRunLoopObserver::isOnRunLoopThread() const noexcept
|
||||||
|
{
|
||||||
|
return CFRunLoopGetCurrent() == runLoop_;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace react
|
||||||
|
} // namespace facebook
|
|
@ -11,6 +11,7 @@
|
||||||
#include <react/componentregistry/ComponentDescriptorFactory.h>
|
#include <react/componentregistry/ComponentDescriptorFactory.h>
|
||||||
#include <react/core/EventBeat.h>
|
#include <react/core/EventBeat.h>
|
||||||
#include <react/utils/ContextContainer.h>
|
#include <react/utils/ContextContainer.h>
|
||||||
|
#include <react/utils/RunLoopObserver.h>
|
||||||
|
|
||||||
namespace facebook {
|
namespace facebook {
|
||||||
namespace react {
|
namespace react {
|
||||||
|
@ -36,6 +37,11 @@ struct SchedulerToolbox final {
|
||||||
*/
|
*/
|
||||||
RuntimeExecutor runtimeExecutor;
|
RuntimeExecutor runtimeExecutor;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Represent connections with a platform-specific UI run loops.
|
||||||
|
*/
|
||||||
|
RunLoopObserver::Factory mainRunLoopObserverFactory;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Asynchronous & synchronous event beats.
|
* Asynchronous & synchronous event beats.
|
||||||
* Represent connections with the platform-specific run loops and general
|
* Represent connections with the platform-specific run loops and general
|
||||||
|
|
Загрузка…
Ссылка в новой задаче