Skip to content

Commit 25a0052

Browse files
cipolleschifacebook-github-bot
authored andcommitted
Refactor subclassing of RCTEventEmitter (facebook#35106)
Summary: Pull Request resolved: facebook#35106 This Diff remove the assert on the initializer in the EventEmitter in place of a more idiomatic check when the method is invoked. It aims to solve an internal error and promotes best practices for the iOS platform. ## Changelog: [iOS][Changed] Refactor RCTEventEmitter initialization Reviewed By: sammy-SC Differential Revision: D40762253 fbshipit-source-id: 83d26616ce147914948e536e9e4b1010758fb690
1 parent ddba780 commit 25a0052

File tree

3 files changed

+90
-11
lines changed

3 files changed

+90
-11
lines changed

React/Modules/RCTEventEmitter.m

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,6 @@ + (NSString *)moduleName
2323
return @"";
2424
}
2525

26-
+ (void)initialize
27-
{
28-
[super initialize];
29-
if (self != [RCTEventEmitter class]) {
30-
RCTAssert(
31-
RCTClassOverridesInstanceMethod(self, @selector(supportedEvents)),
32-
@"You must override the `supportedEvents` method of %@",
33-
self);
34-
}
35-
}
36-
3726
- (instancetype)initWithDisabledObservation
3827
{
3928
self = [super init];
@@ -43,6 +32,9 @@ - (instancetype)initWithDisabledObservation
4332

4433
- (NSArray<NSString *> *)supportedEvents
4534
{
35+
NSString *message =
36+
[NSString stringWithFormat:@"%@ must implement the supportedEvents method", NSStringFromClass(self.class)];
37+
[self _log:message];
4638
return nil;
4739
}
4840

@@ -147,4 +139,15 @@ - (void)invalidate
147139
}
148140
}
149141

142+
#pragma mark - Test utilities
143+
144+
// For testing purposes only.
145+
// This is supposed to be overriden by a subclass in the Tests
146+
// to verified that the error message is actually emitted.
147+
// This is the less intrusive way found to mock the RCTLogError function in unit tests.
148+
- (void)_log:(NSString *)message
149+
{
150+
RCTLogError(@"%@", message);
151+
}
152+
150153
@end

packages/rn-tester/RNTesterPods.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
5C60EB1C226440DB0018C04F /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C60EB1B226440DB0018C04F /* AppDelegate.mm */; };
1818
5CB07C9B226467E60039471C /* RNTesterTurboModuleProvider.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5CB07C99226467E60039471C /* RNTesterTurboModuleProvider.mm */; };
1919
8145AE06241172D900A3F8DA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8145AE05241172D900A3F8DA /* LaunchScreen.storyboard */; };
20+
CD10C7A5290BD4EB0033E1ED /* RCTEventEmitterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CD10C7A4290BD4EB0033E1ED /* RCTEventEmitterTests.m */; };
2021
D19DB1AC8A1EBBFA0D14DB66 /* libPods-RNTester.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 25B78D39CC03C49968A739B2 /* libPods-RNTester.a */; };
2122
DCD006323AC907670B0D60A1 /* libPods-RNTesterUnitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D4E0A9AD185CE086FAC9BD09 /* libPods-RNTesterUnitTests.a */; };
2223
E7C1241A22BEC44B00DA25C0 /* RNTesterIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E7C1241922BEC44B00DA25C0 /* RNTesterIntegrationTests.m */; };
@@ -101,6 +102,7 @@
101102
65B6EA573FF170102920BEF4 /* libPods-RNTesterIntegrationTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RNTesterIntegrationTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
102103
8145AE05241172D900A3F8DA /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = RNTester/LaunchScreen.storyboard; sourceTree = "<group>"; };
103104
8A0B7257DD8B2945456B0F61 /* Pods-RNTesterUnitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RNTesterUnitTests.release.xcconfig"; path = "Target Support Files/Pods-RNTesterUnitTests/Pods-RNTesterUnitTests.release.xcconfig"; sourceTree = "<group>"; };
105+
CD10C7A4290BD4EB0033E1ED /* RCTEventEmitterTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTEventEmitterTests.m; sourceTree = "<group>"; };
104106
D4E0A9AD185CE086FAC9BD09 /* libPods-RNTesterUnitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RNTesterUnitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
105107
E771AEEA22B44E3100EA1189 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = RNTester/Info.plist; sourceTree = "<group>"; };
106108
E7C1241922BEC44B00DA25C0 /* RNTesterIntegrationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNTesterIntegrationTests.m; sourceTree = "<group>"; };
@@ -329,6 +331,7 @@
329331
E7DB20A022B2BA84005AC45F /* RNTesterUnitTests */ = {
330332
isa = PBXGroup;
331333
children = (
334+
CD10C7A4290BD4EB0033E1ED /* RCTEventEmitterTests.m */,
332335
E7DB20A322B2BA84005AC45F /* Info.plist */,
333336
E7DB20C622B2BAA5005AC45F /* RCTAllocationTests.m */,
334337
E7DB20B222B2BAA4005AC45F /* RCTAnimationUtilsTests.m */,
@@ -774,6 +777,7 @@
774777
E7DB20D722B2BAA6005AC45F /* RCTModuleInitTests.m in Sources */,
775778
E7DB20E522B2BAA6005AC45F /* RCTDevMenuTests.m in Sources */,
776779
E7DB20DE22B2BAA6005AC45F /* RCTUnicodeDecodeTests.m in Sources */,
780+
CD10C7A5290BD4EB0033E1ED /* RCTEventEmitterTests.m in Sources */,
777781
E7DB20E422B2BAA6005AC45F /* RCTFormatErrorTests.m in Sources */,
778782
E7DB20EB22B2BAA6005AC45F /* RCTConvert_YGValueTests.m in Sources */,
779783
E7DB20E922B2BAA6005AC45F /* RCTComponentPropsTests.m in Sources */,
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#import <React/RCTEventEmitter.h>
9+
#import <XCTest/XCTest.h>
10+
11+
#pragma mark - Faulty EventEmitter
12+
13+
@interface RCTFaultyEventEmitter : RCTEventEmitter
14+
@end
15+
16+
@implementation RCTFaultyEventEmitter {
17+
NSString *_capturedMessage;
18+
}
19+
20+
- (NSString *)capturedMessage
21+
{
22+
return _capturedMessage;
23+
}
24+
25+
- (void)_log:(NSString *)message
26+
{
27+
_capturedMessage = message;
28+
}
29+
@end
30+
31+
#pragma mark - Proper EventEmitter
32+
33+
@interface RCTProperEventEmitter : RCTEventEmitter
34+
@end
35+
36+
@implementation RCTProperEventEmitter
37+
38+
- (NSArray<NSString *> *)supportedEvents
39+
{
40+
return @[ @"myEvent" ];
41+
}
42+
@end
43+
44+
#pragma mark - Tests Code
45+
46+
@interface RCTEventEmitterTests : XCTestCase
47+
48+
@end
49+
50+
@implementation RCTEventEmitterTests
51+
52+
- (void)testEventEmitterSubclass_whenFaultySubclassInvokesSupportedEvents_raiseException
53+
{
54+
RCTEventEmitter *emitter = [[RCTFaultyEventEmitter alloc] init];
55+
56+
NSArray<NSString *> *events = emitter.supportedEvents;
57+
XCTAssertNil(events);
58+
XCTAssertEqualObjects(
59+
((RCTFaultyEventEmitter *)emitter).capturedMessage,
60+
@"RCTFaultyEventEmitter must implement the supportedEvents method");
61+
}
62+
63+
- (void)testEventEmitterSubclass_whenProperSubclassInvokesSupportedEvents_itreturnsTheEvents
64+
{
65+
RCTEventEmitter *emitter = [[RCTProperEventEmitter alloc] init];
66+
67+
NSArray<NSString *> *events = emitter.supportedEvents;
68+
69+
XCTAssertEqualObjects(events, @[ @"myEvent" ]);
70+
}
71+
72+
@end

0 commit comments

Comments
 (0)