mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Make RCTEventDispatcher TurboModule-compatible
Summary: This diff ended up being a bit more complicated than I anticipated, since the source files in `ReactInternal` were depending on `RCTEventDispatcher`. I made the following changes: 1. Make `RCTEventDispatcher` a `protocol`, keep it in `ReactInternal`. 2. Rename the `RCTEventDispatcher` NativeModule to `RCTEventDispatcherModule`, make it conform to the `RCTEventEmitter` `protocol`, and move it to `CoreModules`. 3. Where necessary, replace categories of `RCTEventDispatcher` with functions. Changelog: [iOS][Added] - Make RCTEventDispatcher TurboModule-comaptible Reviewed By: fkgozali Differential Revision: D18439488 fbshipit-source-id: b3da15c29459fddf884519f33b0c3b8c036b5539
This commit is contained in:
committed by
Facebook GitHub Bot
parent
d5076c6c8f
commit
ea93151f21
@@ -9,7 +9,6 @@
|
||||
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTConvert.h>
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTImageBlurUtils.h>
|
||||
#import <React/RCTImageSource.h>
|
||||
#import <React/RCTImageUtils.h>
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
#import <FBReactNativeSpec/FBReactNativeSpec.h>
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTUtils.h>
|
||||
#import <React/RCTLog.h>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTEventDispatcherProtocol.h>
|
||||
|
||||
#import "RCTValueAnimatedNode.h"
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTEventDispatcherProtocol.h>
|
||||
#import <React/RCTEventEmitter.h>
|
||||
#import <React/RCTSurfacePresenterStub.h>
|
||||
#import <React/RCTUIManager.h>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#import <React/RCTUIManager.h>
|
||||
#import <React/RCTSurfacePresenterStub.h>
|
||||
#import <React/RCTEventDispatcherProtocol.h>
|
||||
|
||||
@protocol RCTValueAnimatedNodeObserver;
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTEventDispatcherProtocol.h>
|
||||
#import <React/RCTEventEmitter.h>
|
||||
#import <React/RCTSurfacePresenterStub.h>
|
||||
#import <React/RCTUIManager.h>
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#import <FBReactNativeSpec/FBReactNativeSpec.h>
|
||||
#import <React/RCTAssert.h>
|
||||
#import <React/RCTConvert.h>
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTLog.h>
|
||||
#import <React/RCTNetworkTask.h>
|
||||
#import <React/RCTNetworking.h>
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#import <FBReactNativeSpec/FBReactNativeSpec.h>
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTConvert.h>
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTUtils.h>
|
||||
|
||||
#import "RCTPushNotificationPlugins.h"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#import <FBReactNativeSpec/FBReactNativeSpec.h>
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTConvert.h>
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTEventDispatcherProtocol.h>
|
||||
#import <React/RCTUtils.h>
|
||||
|
||||
#import "RCTSettingsPlugins.h"
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#import "RCTBackedTextInputViewProtocol.h"
|
||||
|
||||
@class RCTBridge;
|
||||
@class RCTEventDispatcher;
|
||||
@class RCTTextAttributes;
|
||||
@class RCTTextSelection;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTConvert.h>
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTEventDispatcherProtocol.h>
|
||||
#import <React/RCTUIManager.h>
|
||||
#import <React/RCTUtils.h>
|
||||
#import <React/UIView+React.h>
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
@implementation RCTBaseTextInputView {
|
||||
__weak RCTBridge *_bridge;
|
||||
__weak RCTEventDispatcher *_eventDispatcher;
|
||||
__weak id<RCTEventDispatcherProtocol> _eventDispatcher;
|
||||
BOOL _hasInputAccesoryView;
|
||||
NSString *_Nullable _predictedText;
|
||||
BOOL _didMoveToWindow;
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
|
||||
@class JSValue;
|
||||
@class RCTBridge;
|
||||
@class RCTEventDispatcher;
|
||||
@class RCTPerformanceLogger;
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#if RCT_ENABLE_INSPECTOR
|
||||
#import "RCTInspectorDevServerHelper.h"
|
||||
#endif
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTEventDispatcherProtocol.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
||||
@@ -5,14 +5,7 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "RCTEventDispatcher.h"
|
||||
|
||||
#import "RCTAssert.h"
|
||||
#import "RCTBridge+Private.h"
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTComponentEvent.h"
|
||||
#import "RCTProfile.h"
|
||||
#import "RCTUtils.h"
|
||||
#import "RCTEventDispatcherProtocol.h"
|
||||
|
||||
const NSInteger RCTTextUpdateLagWarningThreshold = 3;
|
||||
|
||||
@@ -27,217 +20,11 @@ NSString *RCTNormalizeInputEventName(NSString *eventName)
|
||||
return eventName;
|
||||
}
|
||||
|
||||
static NSNumber *RCTGetEventID(NSNumber *viewTag, NSString *eventName, uint16_t coalescingKey)
|
||||
{
|
||||
return @(viewTag.intValue | (((uint64_t)eventName.hash & 0xFFFF) << 32) | (((uint64_t)coalescingKey) << 48));
|
||||
}
|
||||
|
||||
static uint16_t RCTUniqueCoalescingKeyGenerator = 0;
|
||||
|
||||
@implementation RCTEventDispatcher {
|
||||
// We need this lock to protect access to _events, _eventQueue and _eventsDispatchScheduled. It's filled in on main
|
||||
// thread and consumed on js thread.
|
||||
NSLock *_eventQueueLock;
|
||||
// We have this id -> event mapping so we coalesce effectively.
|
||||
NSMutableDictionary<NSNumber *, id<RCTEvent>> *_events;
|
||||
// This array contains ids of events in order they come in, so we can emit them to JS in the exact same order.
|
||||
NSMutableArray<NSNumber *> *_eventQueue;
|
||||
BOOL _eventsDispatchScheduled;
|
||||
NSHashTable<id<RCTEventDispatcherObserver>> *_observers;
|
||||
NSLock *_observersLock;
|
||||
}
|
||||
|
||||
@synthesize bridge = _bridge;
|
||||
@synthesize dispatchToJSThread = _dispatchToJSThread;
|
||||
@synthesize invokeJS = _invokeJS;
|
||||
@synthesize invokeJSWithModuleDotMethod = _invokeJSWithModuleDotMethod;
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (void)setBridge:(RCTBridge *)bridge
|
||||
{
|
||||
_bridge = bridge;
|
||||
_events = [NSMutableDictionary new];
|
||||
_eventQueue = [NSMutableArray new];
|
||||
_eventQueueLock = [NSLock new];
|
||||
_eventsDispatchScheduled = NO;
|
||||
_observers = [NSHashTable weakObjectsHashTable];
|
||||
_observersLock = [NSLock new];
|
||||
}
|
||||
|
||||
- (void)sendAppEventWithName:(NSString *)name body:(id)body
|
||||
{
|
||||
if (_bridge) {
|
||||
[_bridge enqueueJSCall:@"RCTNativeAppEventEmitter"
|
||||
method:@"emit"
|
||||
args:body ? @[ name, body ] : @[ name ]
|
||||
completion:NULL];
|
||||
} else {
|
||||
_invokeJS(@"RCTNativeAppEventEmitter", @"emit", body ? @[ name, body ] : @[ name ]);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sendDeviceEventWithName:(NSString *)name body:(id)body
|
||||
{
|
||||
if (_bridge) {
|
||||
[_bridge enqueueJSCall:@"RCTDeviceEventEmitter"
|
||||
method:@"emit"
|
||||
args:body ? @[ name, body ] : @[ name ]
|
||||
completion:NULL];
|
||||
} else {
|
||||
_invokeJS(@"RCTDeviceEventEmitter", @"emit", body ? @[ name, body ] : @[ name ]);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sendTextEventWithType:(RCTTextEventType)type
|
||||
reactTag:(NSNumber *)reactTag
|
||||
text:(NSString *)text
|
||||
key:(NSString *)key
|
||||
eventCount:(NSInteger)eventCount
|
||||
{
|
||||
static NSString *events[] = {@"focus", @"blur", @"change", @"submitEditing", @"endEditing", @"keyPress"};
|
||||
|
||||
NSMutableDictionary *body = [[NSMutableDictionary alloc] initWithDictionary:@{
|
||||
@"eventCount" : @(eventCount),
|
||||
}];
|
||||
|
||||
if (text) {
|
||||
body[@"text"] = text;
|
||||
}
|
||||
|
||||
if (key) {
|
||||
if (key.length == 0) {
|
||||
key = @"Backspace"; // backspace
|
||||
} else {
|
||||
switch ([key characterAtIndex:0]) {
|
||||
case '\t':
|
||||
key = @"Tab";
|
||||
break;
|
||||
case '\n':
|
||||
key = @"Enter";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
body[@"key"] = key;
|
||||
}
|
||||
|
||||
RCTComponentEvent *event = [[RCTComponentEvent alloc] initWithName:events[type] viewTag:reactTag body:body];
|
||||
[self sendEvent:event];
|
||||
}
|
||||
|
||||
- (void)sendEvent:(id<RCTEvent>)event
|
||||
{
|
||||
[_observersLock lock];
|
||||
|
||||
for (id<RCTEventDispatcherObserver> observer in _observers) {
|
||||
[observer eventDispatcherWillDispatchEvent:event];
|
||||
}
|
||||
|
||||
[_observersLock unlock];
|
||||
|
||||
[_eventQueueLock lock];
|
||||
|
||||
NSNumber *eventID;
|
||||
if (event.canCoalesce) {
|
||||
eventID = RCTGetEventID(event.viewTag, event.eventName, event.coalescingKey);
|
||||
id<RCTEvent> previousEvent = _events[eventID];
|
||||
if (previousEvent) {
|
||||
event = [previousEvent coalesceWithEvent:event];
|
||||
} else {
|
||||
[_eventQueue addObject:eventID];
|
||||
}
|
||||
} else {
|
||||
id<RCTEvent> previousEvent = _events[eventID];
|
||||
eventID = RCTGetEventID(event.viewTag, event.eventName, RCTUniqueCoalescingKeyGenerator++);
|
||||
RCTAssert(
|
||||
previousEvent == nil,
|
||||
@"Got event %@ which cannot be coalesced, but has the same eventID %@ as the previous event %@",
|
||||
event,
|
||||
eventID,
|
||||
previousEvent);
|
||||
[_eventQueue addObject:eventID];
|
||||
}
|
||||
|
||||
_events[eventID] = event;
|
||||
|
||||
BOOL scheduleEventsDispatch = NO;
|
||||
if (!_eventsDispatchScheduled) {
|
||||
_eventsDispatchScheduled = YES;
|
||||
scheduleEventsDispatch = YES;
|
||||
}
|
||||
|
||||
// We have to release the lock before dispatching block with events,
|
||||
// since dispatchBlock: can be executed synchronously on the same queue.
|
||||
// (This is happening when chrome debugging is turned on.)
|
||||
[_eventQueueLock unlock];
|
||||
|
||||
if (scheduleEventsDispatch) {
|
||||
if (_bridge) {
|
||||
[_bridge
|
||||
dispatchBlock:^{
|
||||
[self flushEventsQueue];
|
||||
}
|
||||
queue:RCTJSThread];
|
||||
} else if (_dispatchToJSThread) {
|
||||
_dispatchToJSThread(^{
|
||||
[self flushEventsQueue];
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)addDispatchObserver:(id<RCTEventDispatcherObserver>)observer
|
||||
{
|
||||
[_observersLock lock];
|
||||
[_observers addObject:observer];
|
||||
[_observersLock unlock];
|
||||
}
|
||||
|
||||
- (void)removeDispatchObserver:(id<RCTEventDispatcherObserver>)observer
|
||||
{
|
||||
[_observersLock lock];
|
||||
[_observers removeObject:observer];
|
||||
[_observersLock unlock];
|
||||
}
|
||||
|
||||
- (void)dispatchEvent:(id<RCTEvent>)event
|
||||
{
|
||||
if (_bridge) {
|
||||
[_bridge enqueueJSCall:[[event class] moduleDotMethod] args:[event arguments]];
|
||||
} else {
|
||||
_invokeJSWithModuleDotMethod([[event class] moduleDotMethod], [event arguments]);
|
||||
}
|
||||
}
|
||||
|
||||
- (dispatch_queue_t)methodQueue
|
||||
{
|
||||
return RCTJSThread;
|
||||
}
|
||||
|
||||
// js thread only (which surprisingly can be the main thread, depends on used JS executor)
|
||||
- (void)flushEventsQueue
|
||||
{
|
||||
[_eventQueueLock lock];
|
||||
NSDictionary *events = _events;
|
||||
_events = [NSMutableDictionary new];
|
||||
NSMutableArray *eventQueue = _eventQueue;
|
||||
_eventQueue = [NSMutableArray new];
|
||||
_eventsDispatchScheduled = NO;
|
||||
[_eventQueueLock unlock];
|
||||
|
||||
for (NSNumber *eventId in eventQueue) {
|
||||
[self dispatchEvent:events[eventId]];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTBridge (RCTEventDispatcher)
|
||||
|
||||
- (RCTEventDispatcher *)eventDispatcher
|
||||
- (id<RCTEventDispatcherProtocol>)eventDispatcher
|
||||
{
|
||||
return [self moduleForClass:[RCTEventDispatcher class]];
|
||||
return [self moduleForName:@"EventDispatcher" lazilyLoadIfNecessary:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -10,15 +10,6 @@
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTJSInvokerModule.h>
|
||||
|
||||
typedef NS_ENUM(NSInteger, RCTTextEventType) {
|
||||
RCTTextEventTypeFocus,
|
||||
RCTTextEventTypeBlur,
|
||||
RCTTextEventTypeChange,
|
||||
RCTTextEventTypeSubmit,
|
||||
RCTTextEventTypeEnd,
|
||||
RCTTextEventTypeKeyPress
|
||||
};
|
||||
|
||||
/**
|
||||
* The threshold at which text inputs will start warning that the JS thread
|
||||
* has fallen behind (resulting in poor input performance, missed keys, etc.)
|
||||
@@ -32,6 +23,15 @@ RCT_EXTERN const NSInteger RCTTextUpdateLagWarningThreshold;
|
||||
*/
|
||||
RCT_EXTERN NSString *RCTNormalizeInputEventName(NSString *eventName);
|
||||
|
||||
typedef NS_ENUM(NSInteger, RCTTextEventType) {
|
||||
RCTTextEventTypeFocus,
|
||||
RCTTextEventTypeBlur,
|
||||
RCTTextEventTypeChange,
|
||||
RCTTextEventTypeSubmit,
|
||||
RCTTextEventTypeEnd,
|
||||
RCTTextEventTypeKeyPress
|
||||
};
|
||||
|
||||
@protocol RCTEvent <NSObject>
|
||||
@required
|
||||
|
||||
@@ -80,7 +80,7 @@ RCT_EXTERN NSString *RCTNormalizeInputEventName(NSString *eventName);
|
||||
* This class wraps the -[RCTBridge enqueueJSCall:args:] method, and
|
||||
* provides some convenience methods for generating event calls.
|
||||
*/
|
||||
@interface RCTEventDispatcher : NSObject <RCTBridgeModule, RCTJSDispatcherModule, RCTJSInvokerModule>
|
||||
@protocol RCTEventDispatcherProtocol <RCTBridgeModule, RCTJSDispatcherModule, RCTJSInvokerModule>
|
||||
|
||||
/**
|
||||
* Deprecated, do not use.
|
||||
@@ -123,6 +123,6 @@ RCT_EXTERN NSString *RCTNormalizeInputEventName(NSString *eventName);
|
||||
|
||||
@interface RCTBridge (RCTEventDispatcher)
|
||||
|
||||
- (RCTEventDispatcher *)eventDispatcher;
|
||||
- (id<RCTEventDispatcherProtocol>)eventDispatcher;
|
||||
|
||||
@end
|
||||
@@ -15,7 +15,6 @@
|
||||
#import "RCTBridge+Private.h"
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTConstants.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTKeyCommands.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTPerformanceLogger.h"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTEventDispatcherProtocol.h>
|
||||
|
||||
/**
|
||||
* Represents a touch event, which may be composed of several touches (one for every finger).
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#import "RCTAssert.h"
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTEventDispatcherProtocol.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTSurfaceView.h"
|
||||
#import "RCTTouchEvent.h"
|
||||
@@ -25,7 +25,7 @@
|
||||
// TODO: this class behaves a lot like a module, and could be implemented as a
|
||||
// module if we were to assume that modules and RootViews had a 1:1 relationship
|
||||
@implementation RCTTouchHandler {
|
||||
__weak RCTEventDispatcher *_eventDispatcher;
|
||||
__weak id<RCTEventDispatcherProtocol> _eventDispatcher;
|
||||
|
||||
/**
|
||||
* Arrays managed in parallel tracking native touch object along with the
|
||||
@@ -47,7 +47,7 @@
|
||||
RCTAssertParam(bridge);
|
||||
|
||||
if ((self = [super initWithTarget:nil action:NULL])) {
|
||||
_eventDispatcher = [bridge moduleForClass:[RCTEventDispatcher class]];
|
||||
_eventDispatcher = bridge.eventDispatcher;
|
||||
|
||||
_nativeTouches = [NSMutableOrderedSet new];
|
||||
_reactTouches = [NSMutableArray new];
|
||||
|
||||
@@ -117,6 +117,9 @@ rn_apple_library(
|
||||
) + react_module_plugin_providers(
|
||||
name = "DevSplitBundleLoader",
|
||||
native_class_func = "RCTDevSplitBundleLoaderCls",
|
||||
) + react_module_plugin_providers(
|
||||
name = "EventDispatcher",
|
||||
native_class_func = "RCTEventDispatcherCls",
|
||||
),
|
||||
plugins_header = "FBCoreModulesPlugins.h",
|
||||
preprocessor_flags = OBJC_ARC_PREPROCESSOR_FLAGS + get_preprocessor_flags_for_build_mode() + rn_extra_build_flags() + [
|
||||
|
||||
@@ -53,6 +53,7 @@ Class RCTWebSocketExecutorCls(void) __attribute__((used));
|
||||
Class RCTWebSocketModuleCls(void) __attribute__((used));
|
||||
Class RCTDevLoadingViewCls(void) __attribute__((used));
|
||||
Class RCTDevSplitBundleLoaderCls(void) __attribute__((used));
|
||||
Class RCTEventDispatcherCls(void) __attribute__((used));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ Class RCTCoreModulesClassProvider(const char *name) {
|
||||
{"WebSocketModule", RCTWebSocketModuleCls},
|
||||
{"DevLoadingView", RCTDevLoadingViewCls},
|
||||
{"DevSplitBundleLoader", RCTDevSplitBundleLoaderCls},
|
||||
{"EventDispatcher", RCTEventDispatcherCls},
|
||||
};
|
||||
|
||||
auto p = sCoreModuleClassMap.find(name);
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#import <FBReactNativeSpec/FBReactNativeSpec.h>
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTConvert.h>
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTEventDispatcherProtocol.h>
|
||||
#import <React/RCTLog.h>
|
||||
#import <React/RCTUIManager.h>
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#import <FBReactNativeSpec/FBReactNativeSpec.h>
|
||||
#import <React/RCTAssert.h>
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTEventDispatcherProtocol.h>
|
||||
#import <React/RCTUtils.h>
|
||||
|
||||
#import "CoreModulesPlugins.h"
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#import <FBReactNativeSpec/FBReactNativeSpec.h>
|
||||
#import <React/RCTBridge+Private.h>
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTEventDispatcherProtocol.h>
|
||||
#import <React/RCTLog.h>
|
||||
#import <React/RCTProfile.h>
|
||||
#import <React/RCTReloadCommand.h>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#import <React/RCTAccessibilityManager.h>
|
||||
#import <React/RCTAssert.h>
|
||||
#import <React/RCTConstants.h>
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTEventDispatcherProtocol.h>
|
||||
#import <React/RCTUIUtils.h>
|
||||
#import <React/RCTUtils.h>
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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/RCTBridge.h>
|
||||
#import <React/RCTEventDispatcherProtocol.h>
|
||||
/**
|
||||
* This class wraps the -[RCTBridge enqueueJSCall:args:] method, and
|
||||
* provides some convenience methods for generating event calls.
|
||||
*/
|
||||
@interface RCTEventDispatcher : NSObject <RCTEventDispatcherProtocol>
|
||||
@end
|
||||
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* 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 "RCTEventDispatcher.h"
|
||||
|
||||
#import <React/RCTAssert.h>
|
||||
#import <React/RCTBridge+Private.h>
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTComponentEvent.h>
|
||||
#import <React/RCTProfile.h>
|
||||
#import <React/RCTUtils.h>
|
||||
#import <ReactCommon/RCTTurboModule.h>
|
||||
|
||||
#import "CoreModulesPlugins.h"
|
||||
|
||||
static NSNumber *RCTGetEventID(NSNumber *viewTag, NSString *eventName, uint16_t coalescingKey)
|
||||
{
|
||||
return @(viewTag.intValue | (((uint64_t)eventName.hash & 0xFFFF) << 32) | (((uint64_t)coalescingKey) << 48));
|
||||
}
|
||||
|
||||
static uint16_t RCTUniqueCoalescingKeyGenerator = 0;
|
||||
|
||||
@interface RCTEventDispatcher () <RCTTurboModule>
|
||||
@end
|
||||
|
||||
@implementation RCTEventDispatcher {
|
||||
// We need this lock to protect access to _events, _eventQueue and _eventsDispatchScheduled. It's filled in on main
|
||||
// thread and consumed on js thread.
|
||||
NSLock *_eventQueueLock;
|
||||
// We have this id -> event mapping so we coalesce effectively.
|
||||
NSMutableDictionary<NSNumber *, id<RCTEvent>> *_events;
|
||||
// This array contains ids of events in order they come in, so we can emit them to JS in the exact same order.
|
||||
NSMutableArray<NSNumber *> *_eventQueue;
|
||||
BOOL _eventsDispatchScheduled;
|
||||
NSHashTable<id<RCTEventDispatcherObserver>> *_observers;
|
||||
NSLock *_observersLock;
|
||||
}
|
||||
|
||||
@synthesize bridge = _bridge;
|
||||
@synthesize dispatchToJSThread = _dispatchToJSThread;
|
||||
@synthesize invokeJS = _invokeJS;
|
||||
@synthesize invokeJSWithModuleDotMethod = _invokeJSWithModuleDotMethod;
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (void)setBridge:(RCTBridge *)bridge
|
||||
{
|
||||
_bridge = bridge;
|
||||
_events = [NSMutableDictionary new];
|
||||
_eventQueue = [NSMutableArray new];
|
||||
_eventQueueLock = [NSLock new];
|
||||
_eventsDispatchScheduled = NO;
|
||||
_observers = [NSHashTable weakObjectsHashTable];
|
||||
_observersLock = [NSLock new];
|
||||
}
|
||||
|
||||
- (void)sendAppEventWithName:(NSString *)name body:(id)body
|
||||
{
|
||||
if (_bridge) {
|
||||
[_bridge enqueueJSCall:@"RCTNativeAppEventEmitter"
|
||||
method:@"emit"
|
||||
args:body ? @[ name, body ] : @[ name ]
|
||||
completion:NULL];
|
||||
} else {
|
||||
_invokeJS(@"RCTNativeAppEventEmitter", @"emit", body ? @[ name, body ] : @[ name ]);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sendDeviceEventWithName:(NSString *)name body:(id)body
|
||||
{
|
||||
if (_bridge) {
|
||||
[_bridge enqueueJSCall:@"RCTDeviceEventEmitter"
|
||||
method:@"emit"
|
||||
args:body ? @[ name, body ] : @[ name ]
|
||||
completion:NULL];
|
||||
} else {
|
||||
_invokeJS(@"RCTDeviceEventEmitter", @"emit", body ? @[ name, body ] : @[ name ]);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sendTextEventWithType:(RCTTextEventType)type
|
||||
reactTag:(NSNumber *)reactTag
|
||||
text:(NSString *)text
|
||||
key:(NSString *)key
|
||||
eventCount:(NSInteger)eventCount
|
||||
{
|
||||
static NSString *events[] = {@"focus", @"blur", @"change", @"submitEditing", @"endEditing", @"keyPress"};
|
||||
|
||||
NSMutableDictionary *body = [[NSMutableDictionary alloc] initWithDictionary:@{
|
||||
@"eventCount" : @(eventCount),
|
||||
}];
|
||||
|
||||
if (text) {
|
||||
body[@"text"] = text;
|
||||
}
|
||||
|
||||
if (key) {
|
||||
if (key.length == 0) {
|
||||
key = @"Backspace"; // backspace
|
||||
} else {
|
||||
switch ([key characterAtIndex:0]) {
|
||||
case '\t':
|
||||
key = @"Tab";
|
||||
break;
|
||||
case '\n':
|
||||
key = @"Enter";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
body[@"key"] = key;
|
||||
}
|
||||
|
||||
RCTComponentEvent *event = [[RCTComponentEvent alloc] initWithName:events[type] viewTag:reactTag body:body];
|
||||
[self sendEvent:event];
|
||||
}
|
||||
|
||||
- (void)sendEvent:(id<RCTEvent>)event
|
||||
{
|
||||
[_observersLock lock];
|
||||
|
||||
for (id<RCTEventDispatcherObserver> observer in _observers) {
|
||||
[observer eventDispatcherWillDispatchEvent:event];
|
||||
}
|
||||
|
||||
[_observersLock unlock];
|
||||
|
||||
[_eventQueueLock lock];
|
||||
|
||||
NSNumber *eventID;
|
||||
if (event.canCoalesce) {
|
||||
eventID = RCTGetEventID(event.viewTag, event.eventName, event.coalescingKey);
|
||||
id<RCTEvent> previousEvent = _events[eventID];
|
||||
if (previousEvent) {
|
||||
event = [previousEvent coalesceWithEvent:event];
|
||||
} else {
|
||||
[_eventQueue addObject:eventID];
|
||||
}
|
||||
} else {
|
||||
id<RCTEvent> previousEvent = _events[eventID];
|
||||
eventID = RCTGetEventID(event.viewTag, event.eventName, RCTUniqueCoalescingKeyGenerator++);
|
||||
RCTAssert(
|
||||
previousEvent == nil,
|
||||
@"Got event %@ which cannot be coalesced, but has the same eventID %@ as the previous event %@",
|
||||
event,
|
||||
eventID,
|
||||
previousEvent);
|
||||
[_eventQueue addObject:eventID];
|
||||
}
|
||||
|
||||
_events[eventID] = event;
|
||||
|
||||
BOOL scheduleEventsDispatch = NO;
|
||||
if (!_eventsDispatchScheduled) {
|
||||
_eventsDispatchScheduled = YES;
|
||||
scheduleEventsDispatch = YES;
|
||||
}
|
||||
|
||||
// We have to release the lock before dispatching block with events,
|
||||
// since dispatchBlock: can be executed synchronously on the same queue.
|
||||
// (This is happening when chrome debugging is turned on.)
|
||||
[_eventQueueLock unlock];
|
||||
|
||||
if (scheduleEventsDispatch) {
|
||||
if (_bridge) {
|
||||
[_bridge
|
||||
dispatchBlock:^{
|
||||
[self flushEventsQueue];
|
||||
}
|
||||
queue:RCTJSThread];
|
||||
} else if (_dispatchToJSThread) {
|
||||
_dispatchToJSThread(^{
|
||||
[self flushEventsQueue];
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)addDispatchObserver:(id<RCTEventDispatcherObserver>)observer
|
||||
{
|
||||
[_observersLock lock];
|
||||
[_observers addObject:observer];
|
||||
[_observersLock unlock];
|
||||
}
|
||||
|
||||
- (void)removeDispatchObserver:(id<RCTEventDispatcherObserver>)observer
|
||||
{
|
||||
[_observersLock lock];
|
||||
[_observers removeObject:observer];
|
||||
[_observersLock unlock];
|
||||
}
|
||||
|
||||
- (void)dispatchEvent:(id<RCTEvent>)event
|
||||
{
|
||||
if (_bridge) {
|
||||
[_bridge enqueueJSCall:[[event class] moduleDotMethod] args:[event arguments]];
|
||||
} else {
|
||||
_invokeJSWithModuleDotMethod([[event class] moduleDotMethod], [event arguments]);
|
||||
}
|
||||
}
|
||||
|
||||
- (dispatch_queue_t)methodQueue
|
||||
{
|
||||
return RCTJSThread;
|
||||
}
|
||||
|
||||
// js thread only (which surprisingly can be the main thread, depends on used JS executor)
|
||||
- (void)flushEventsQueue
|
||||
{
|
||||
[_eventQueueLock lock];
|
||||
NSDictionary *events = _events;
|
||||
_events = [NSMutableDictionary new];
|
||||
NSMutableArray *eventQueue = _eventQueue;
|
||||
_eventQueue = [NSMutableArray new];
|
||||
_eventsDispatchScheduled = NO;
|
||||
[_eventQueueLock unlock];
|
||||
|
||||
for (NSNumber *eventId in eventQueue) {
|
||||
[self dispatchEvent:events[eventId]];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Class RCTEventDispatcherCls(void)
|
||||
{
|
||||
return RCTEventDispatcher.class;
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
#import "RCTKeyboardObserver.h"
|
||||
|
||||
#import <FBReactNativeSpec/FBReactNativeSpec.h>
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTEventDispatcherProtocol.h>
|
||||
|
||||
#import "CoreModulesPlugins.h"
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#import <React/RCTConvert.h>
|
||||
#import <React/RCTDefines.h>
|
||||
#import <React/RCTErrorInfo.h>
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTEventDispatcherProtocol.h>
|
||||
#import <React/RCTJSStackFrame.h>
|
||||
#import <React/RCTRedBoxExtraDataViewController.h>
|
||||
#import <React/RCTRedBoxSetEnabled.h>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#import "RCTStatusBarManager.h"
|
||||
#import "CoreModulesPlugins.h"
|
||||
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTEventDispatcherProtocol.h>
|
||||
#import <React/RCTLog.h>
|
||||
#import <React/RCTUtils.h>
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#import "RCTComponentData.h"
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTDefines.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTEventDispatcherProtocol.h"
|
||||
#import "RCTLayoutAnimation.h"
|
||||
#import "RCTLayoutAnimationGroup.h"
|
||||
#import "RCTLog.h"
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#import <React/RCTUIManager.h>
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTDatePicker.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "UIView+React.h"
|
||||
|
||||
@implementation RCTConvert (UIDatePicker)
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#import "RCTSegmentedControl.h"
|
||||
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "UIView+React.h"
|
||||
|
||||
@implementation RCTSegmentedControl
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#import "RCTSliderManager.h"
|
||||
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTSlider.h"
|
||||
#import "UIView+React.h"
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
#import "RCTSwitch.h"
|
||||
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "UIView+React.h"
|
||||
|
||||
@implementation RCTSwitch
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
#import <React/RCTUIManager.h>
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTSwitch.h"
|
||||
#import "UIView+React.h"
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#import <React/RCTConvert.h>
|
||||
#import <React/RCTDefines.h>
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTEventDispatcherProtocol.h>
|
||||
#import <React/RCTLog.h>
|
||||
#import <React/UIView+React.h>
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTConvert+Transform.h"
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTShadowView.h"
|
||||
#import "RCTUIManager.h"
|
||||
|
||||
@@ -10,14 +10,12 @@
|
||||
#import <UIKit/UIScrollView.h>
|
||||
|
||||
#import "RCTAutoInsetsProtocol.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTUtils.h"
|
||||
#import "UIView+React.h"
|
||||
|
||||
@implementation RCTWrapperViewController {
|
||||
UIView *_wrapperView;
|
||||
UIView *_contentView;
|
||||
RCTEventDispatcher *_eventDispatcher;
|
||||
CGFloat _previousTopLayoutLength;
|
||||
CGFloat _previousBottomLayoutLength;
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTEventDispatcherProtocol.h>
|
||||
|
||||
@interface RCTScrollEvent : NSObject <RCTEvent>
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
#import <UIKit/UIScrollView.h>
|
||||
|
||||
#import <React/RCTAutoInsetsProtocol.h>
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTDefines.h>
|
||||
#import <React/RCTEventDispatcherProtocol.h>
|
||||
#import <React/RCTScrollableProtocol.h>
|
||||
#import <React/RCTView.h>
|
||||
|
||||
@@ -16,7 +17,7 @@
|
||||
|
||||
@interface RCTScrollView : RCTView <UIScrollViewDelegate, RCTScrollableProtocol, RCTAutoInsetsProtocol>
|
||||
|
||||
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;
|
||||
- (instancetype)initWithEventDispatcher:(id<RCTEventDispatcherProtocol>)eventDispatcher NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
* The `RCTScrollView` may have at most one single subview. This will ensure
|
||||
@@ -71,11 +72,4 @@
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTEventDispatcher (RCTScrollView)
|
||||
|
||||
/**
|
||||
* Send a fake scroll event.
|
||||
*/
|
||||
- (void)sendFakeScrollEvent:(NSNumber *)reactTag;
|
||||
|
||||
@end
|
||||
RCT_EXTERN void RCTSendFakeScrollEvent(id<RCTEventDispatcherProtocol> eventDispatcher, NSNumber *reactTag);
|
||||
|
||||
@@ -261,7 +261,7 @@
|
||||
@end
|
||||
|
||||
@implementation RCTScrollView {
|
||||
RCTEventDispatcher *_eventDispatcher;
|
||||
id<RCTEventDispatcherProtocol> _eventDispatcher;
|
||||
CGRect _prevFirstVisibleFrame;
|
||||
__weak UIView *_firstVisibleView;
|
||||
RCTCustomScrollView *_scrollView;
|
||||
@@ -275,7 +275,7 @@
|
||||
NSHashTable *_scrollListeners;
|
||||
}
|
||||
|
||||
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
- (instancetype)initWithEventDispatcher:(id<RCTEventDispatcherProtocol>)eventDispatcher
|
||||
{
|
||||
RCTAssertParam(eventDispatcher);
|
||||
|
||||
@@ -1022,9 +1022,7 @@ RCT_SET_AND_PRESERVE_OFFSET(setScrollIndicatorInsets, scrollIndicatorInsets, UIE
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTEventDispatcher (RCTScrollView)
|
||||
|
||||
- (void)sendFakeScrollEvent:(NSNumber *)reactTag
|
||||
void RCTSendFakeScrollEvent(id<RCTEventDispatcherProtocol> eventDispatcher, NSNumber *reactTag)
|
||||
{
|
||||
// Use the selector here in case the onScroll block property is ever renamed
|
||||
NSString *eventName = NSStringFromSelector(@selector(onScroll));
|
||||
@@ -1037,7 +1035,5 @@ RCT_SET_AND_PRESERVE_OFFSET(setScrollIndicatorInsets, scrollIndicatorInsets, UIE
|
||||
scrollViewZoomScale:0
|
||||
userData:nil
|
||||
coalescingKey:0];
|
||||
[self sendEvent:fakeScrollEvent];
|
||||
[eventDispatcher sendEvent:fakeScrollEvent];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+1
@@ -9,6 +9,7 @@
|
||||
#include <React/RCTBridge+Private.h>
|
||||
#include <React/RCTBridgeMethod.h>
|
||||
#include <React/RCTComponentData.h>
|
||||
#include <React/RCTEventDispatcherProtocol.h>
|
||||
#include <React/RCTFollyConvert.h>
|
||||
#include <React/RCTModuleData.h>
|
||||
#include <React/RCTUIManager.h>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#import "RCTTestModule.h"
|
||||
|
||||
#import <React/RCTAssert.h>
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTEventDispatcherProtocol.h>
|
||||
#import <React/RCTLog.h>
|
||||
#import <React/RCTUIManager.h>
|
||||
#import <ReactCommon/RCTTurboModule.h>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import <RCTTest/RCTTestRunner.h>
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTEventDispatcherProtocol.h>
|
||||
#import <React/RCTRootView.h>
|
||||
#import <React/RCTRootViewDelegate.h>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user