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/core/LayoutConstraints.h>
|
||||
#import <react/core/LayoutContext.h>
|
||||
#import <react/scheduler/AsynchronousEventBeat.h>
|
||||
#import <react/scheduler/SchedulerToolbox.h>
|
||||
#import <react/scheduler/SynchronousEventBeat.h>
|
||||
#import <react/utils/ContextContainer.h>
|
||||
#import <react/utils/ManagedObjectWrapper.h>
|
||||
|
||||
#import "MainRunLoopEventBeat.h"
|
||||
#import "PlatformRunLoopObserver.h"
|
||||
#import "RCTConversions.h"
|
||||
#import "RuntimeEventBeat.h"
|
||||
|
||||
|
@ -275,6 +278,8 @@ static inline LayoutContext RCTGetLayoutContext()
|
|||
|
||||
- (RCTScheduler *)_createScheduler
|
||||
{
|
||||
auto reactNativeConfig = _contextContainer->at<std::shared_ptr<ReactNativeConfig const>>("ReactNativeConfig");
|
||||
|
||||
auto componentRegistryFactory =
|
||||
[factory = wrapManagedObject(_mountingManager.componentViewRegistry.componentViewFactory)](
|
||||
EventDispatcher::Weak const &eventDispatcher, ContextContainer::Shared const &contextContainer) {
|
||||
|
@ -288,7 +293,24 @@ static inline LayoutContext RCTGetLayoutContext()
|
|||
toolbox.contextContainer = _contextContainer;
|
||||
toolbox.componentRegistryFactory = componentRegistryFactory;
|
||||
toolbox.runtimeExecutor = runtimeExecutor;
|
||||
toolbox.mainRunLoopObserverFactory = [](RunLoopObserver::Activity activities,
|
||||
RunLoopObserver::WeakOwner const &owner) {
|
||||
return std::make_unique<MainRunLoopObserver>(activities, owner);
|
||||
};
|
||||
|
||||
if (reactNativeConfig && reactNativeConfig->getBool("react_fabric:enable_run_loop_based_event_beat_ios")) {
|
||||
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);
|
||||
};
|
||||
|
@ -296,11 +318,11 @@ static inline LayoutContext RCTGetLayoutContext()
|
|||
toolbox.asynchronousEventBeatFactory = [runtimeExecutor](EventBeat::SharedOwnerBox const &ownerBox) {
|
||||
return std::make_unique<RuntimeEventBeat>(ownerBox, runtimeExecutor);
|
||||
};
|
||||
}
|
||||
|
||||
RCTScheduler *scheduler = [[RCTScheduler alloc] initWithToolbox:toolbox];
|
||||
scheduler.delegate = self;
|
||||
|
||||
auto reactNativeConfig = _contextContainer->at<std::shared_ptr<ReactNativeConfig const>>("ReactNativeConfig");
|
||||
if (reactNativeConfig) {
|
||||
_mountingManager.useModernDifferentiatorMode =
|
||||
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/core/EventBeat.h>
|
||||
#include <react/utils/ContextContainer.h>
|
||||
#include <react/utils/RunLoopObserver.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
@ -36,6 +37,11 @@ struct SchedulerToolbox final {
|
|||
*/
|
||||
RuntimeExecutor runtimeExecutor;
|
||||
|
||||
/*
|
||||
* Represent connections with a platform-specific UI run loops.
|
||||
*/
|
||||
RunLoopObserver::Factory mainRunLoopObserverFactory;
|
||||
|
||||
/*
|
||||
* Asynchronous & synchronous event beats.
|
||||
* Represent connections with the platform-specific run loops and general
|
||||
|
|
Загрузка…
Ссылка в новой задаче