mirror of
https://github.com/status-im/react-native.git
synced 2025-02-22 06:08:24 +00:00
Summary: The `EmitterSubscription.remove()` method was previously calling `this.subscriber.removeSubscription(this)` directly, bypassing the mechanism in `NativeEventEmitter` that keeps track of the number of subscriptions. This meant that native event modules (subclasses of `RCTEventEmitter`) would keep sending events even after all the listeners had been removed. This wasn't a huge overhead, since these modules are singletons and only send one message over the bridge per event, regardless of the number of listeners, but it's still undesirable. This fixes the problem by routing the `EmitterSubscription.remove()` method through the `EventEmitter` so that `NativeEventEmitter` can apply the additional native calls. I've also improved the architecture so that each `NativeEventEmitter` uses its own `EventEmitter`, but they currently all still share the same `EventSubscriptionVendor` so that legacy code which registers events via `RCTDeviceEventEmitter` still works. Reviewed By: vjeux Differential Revision: D3292361 fbshipit-source-id: d60e881d50351523d2112473703bea826641cdef
85 lines
1.9 KiB
Objective-C
85 lines
1.9 KiB
Objective-C
/**
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*/
|
|
|
|
#import "RCTEventEmitter.h"
|
|
#import "RCTAssert.h"
|
|
#import "RCTLog.h"
|
|
|
|
@implementation RCTEventEmitter
|
|
{
|
|
NSInteger _listenerCount;
|
|
}
|
|
|
|
+ (NSString *)moduleName
|
|
{
|
|
return @"";
|
|
}
|
|
|
|
- (NSArray<NSString *> *)supportedEvents
|
|
{
|
|
RCTAssert(NO, @"You must override the `supportedEvents` method of %@", [self class]);
|
|
return nil;
|
|
}
|
|
|
|
- (void)sendEventWithName:(NSString *)eventName body:(id)body
|
|
{
|
|
RCTAssert(_bridge != nil, @"bridge is not set.");
|
|
|
|
if (RCT_DEBUG && ![[self supportedEvents] containsObject:eventName]) {
|
|
RCTLogError(@"`%@` is not a supported event type for %@", eventName, [self class]);
|
|
}
|
|
if (_listenerCount > 0) {
|
|
[_bridge enqueueJSCall:@"RCTDeviceEventEmitter.emit"
|
|
args:body ? @[eventName, body] : @[eventName]];
|
|
} else {
|
|
RCTLogWarn(@"Sending `%@` with no listeners registered.", eventName);
|
|
}
|
|
}
|
|
|
|
- (void)startObserving
|
|
{
|
|
// Does nothing
|
|
}
|
|
|
|
- (void)stopObserving
|
|
{
|
|
// Does nothing
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
if (_listenerCount > 0) {
|
|
[self stopObserving];
|
|
}
|
|
}
|
|
|
|
RCT_EXPORT_METHOD(addListener:(NSString *)eventName)
|
|
{
|
|
if (RCT_DEBUG && ![[self supportedEvents] containsObject:eventName]) {
|
|
RCTLogError(@"`%@` is not a supported event type for %@", eventName, [self class]);
|
|
}
|
|
if (_listenerCount == 0) {
|
|
[self startObserving];
|
|
}
|
|
_listenerCount++;
|
|
}
|
|
|
|
RCT_EXPORT_METHOD(removeListeners:(NSInteger)count)
|
|
{
|
|
if (RCT_DEBUG && count > _listenerCount) {
|
|
RCTLogError(@"Attempted to remove more %@ listeners than added", [self class]);
|
|
}
|
|
if (count == _listenerCount) {
|
|
[self stopObserving];
|
|
}
|
|
_listenerCount -= count;
|
|
}
|
|
|
|
@end
|