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:
Valentin Shergin 2020-05-10 21:29:32 -07:00 коммит произвёл Facebook GitHub Bot
Родитель ebdd59aff8
Коммит f05fff6a68
4 изменённых файлов: 186 добавлений и 7 удалений

Просмотреть файл

@ -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,19 +293,36 @@ static inline LayoutContext RCTGetLayoutContext()
toolbox.contextContainer = _contextContainer;
toolbox.componentRegistryFactory = componentRegistryFactory;
toolbox.runtimeExecutor = runtimeExecutor;
toolbox.synchronousEventBeatFactory = [runtimeExecutor](EventBeat::SharedOwnerBox const &ownerBox) {
return std::make_unique<MainRunLoopEventBeat>(ownerBox, runtimeExecutor);
toolbox.mainRunLoopObserverFactory = [](RunLoopObserver::Activity activities,
RunLoopObserver::WeakOwner const &owner) {
return std::make_unique<MainRunLoopObserver>(activities, owner);
};
toolbox.asynchronousEventBeatFactory = [runtimeExecutor](EventBeat::SharedOwnerBox const &ownerBox) {
return std::make_unique<RuntimeEventBeat>(ownerBox, runtimeExecutor);
};
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);
};
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