RN iOS: Support View Manager Commands that are strings
Summary:
Right now JS triggers a view manager command with the following code:
```
UIManager.dispatchViewManagerCommand(
nullthrows(this.scrollResponderGetScrollableNode()),
UIManager.getViewManagerConfig('RCTScrollView').Commands.scrollTo,
[x || 0, y || 0, animated !== false],
);
```
As we want to get rid of calls to UIManager, we need to stop looking for the integer defined in native from JavaScript. We will be changing methods like this to be:
```
UIManager.dispatchViewManagerCommand(
nullthrows(this.scrollResponderGetScrollableNode()),
'scrollTo',
[x || 0, y || 0, animated !== false],
);
```
We need to support ints and Strings to be backwards compatible, but ints will be deprecated.
This is the same change as made for Android here: 3cae6fa950
Reviewed By: PeteTheHeat
Differential Revision: D15983041
fbshipit-source-id: 6cb0f3001553d1f9d26e7e8fb5481e16fbca6847
This commit is contained in:
Родитель
1dbc38ad93
Коммит
0a34fb78ab
|
@ -44,6 +44,12 @@ typedef id<RCTBridgeModule>(^RCTBridgeModuleProvider)(void);
|
|||
*/
|
||||
@property (nonatomic, copy, readonly) NSArray<id<RCTBridgeMethod>> *methods;
|
||||
|
||||
/**
|
||||
* Returns a map of the module methods. Note that this will gather the methods the first
|
||||
* time it is called and then memoize the results.
|
||||
*/
|
||||
@property (nonatomic, copy, readonly) NSDictionary<NSString *, id<RCTBridgeMethod>> *methodsByName;
|
||||
|
||||
/**
|
||||
* Returns the module's constants, if it exports any
|
||||
*/
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
}
|
||||
|
||||
@synthesize methods = _methods;
|
||||
@synthesize methodsByName = _methodsByName;
|
||||
@synthesize instance = _instance;
|
||||
@synthesize methodQueue = _methodQueue;
|
||||
|
||||
|
@ -225,6 +226,47 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init);
|
|||
}
|
||||
}
|
||||
|
||||
- (void) calculateMethods
|
||||
{
|
||||
if (_methods && _methodsByName) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSMutableArray<id<RCTBridgeMethod>> *moduleMethods = [NSMutableArray new];
|
||||
NSMutableDictionary<NSString *, id<RCTBridgeMethod>> *moduleMethodsByName = [NSMutableDictionary new];
|
||||
|
||||
if ([_moduleClass instancesRespondToSelector:@selector(methodsToExport)]) {
|
||||
[moduleMethods addObjectsFromArray:[self.instance methodsToExport]];
|
||||
}
|
||||
|
||||
unsigned int methodCount;
|
||||
Class cls = _moduleClass;
|
||||
while (cls && cls != [NSObject class] && cls != [NSProxy class]) {
|
||||
Method *methods = class_copyMethodList(object_getClass(cls), &methodCount);
|
||||
|
||||
for (unsigned int i = 0; i < methodCount; i++) {
|
||||
Method method = methods[i];
|
||||
SEL selector = method_getName(method);
|
||||
if ([NSStringFromSelector(selector) hasPrefix:@"__rct_export__"]) {
|
||||
IMP imp = method_getImplementation(method);
|
||||
auto exportedMethod = ((const RCTMethodInfo *(*)(id, SEL))imp)(_moduleClass, selector);
|
||||
id<RCTBridgeMethod> moduleMethod = [[RCTModuleMethod alloc] initWithExportedMethod:exportedMethod
|
||||
moduleClass:_moduleClass];
|
||||
|
||||
NSString *str = [NSString stringWithUTF8String:moduleMethod.JSMethodName];
|
||||
[moduleMethodsByName setValue:moduleMethod forKey:str];
|
||||
[moduleMethods addObject:moduleMethod];
|
||||
}
|
||||
}
|
||||
|
||||
free(methods);
|
||||
cls = class_getSuperclass(cls);
|
||||
}
|
||||
|
||||
_methods = [moduleMethods copy];
|
||||
_methodsByName = [moduleMethodsByName copy];
|
||||
}
|
||||
|
||||
#pragma mark - public getters
|
||||
|
||||
- (BOOL)hasInstance
|
||||
|
@ -267,37 +309,14 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init);
|
|||
|
||||
- (NSArray<id<RCTBridgeMethod>> *)methods
|
||||
{
|
||||
if (!_methods) {
|
||||
NSMutableArray<id<RCTBridgeMethod>> *moduleMethods = [NSMutableArray new];
|
||||
[self calculateMethods];
|
||||
return _methods;
|
||||
}
|
||||
|
||||
if ([_moduleClass instancesRespondToSelector:@selector(methodsToExport)]) {
|
||||
[moduleMethods addObjectsFromArray:[self.instance methodsToExport]];
|
||||
}
|
||||
|
||||
unsigned int methodCount;
|
||||
Class cls = _moduleClass;
|
||||
while (cls && cls != [NSObject class] && cls != [NSProxy class]) {
|
||||
Method *methods = class_copyMethodList(object_getClass(cls), &methodCount);
|
||||
|
||||
for (unsigned int i = 0; i < methodCount; i++) {
|
||||
Method method = methods[i];
|
||||
SEL selector = method_getName(method);
|
||||
if ([NSStringFromSelector(selector) hasPrefix:@"__rct_export__"]) {
|
||||
IMP imp = method_getImplementation(method);
|
||||
auto exportedMethod = ((const RCTMethodInfo *(*)(id, SEL))imp)(_moduleClass, selector);
|
||||
id<RCTBridgeMethod> moduleMethod = [[RCTModuleMethod alloc] initWithExportedMethod:exportedMethod
|
||||
moduleClass:_moduleClass];
|
||||
[moduleMethods addObject:moduleMethod];
|
||||
}
|
||||
}
|
||||
|
||||
free(methods);
|
||||
cls = class_getSuperclass(cls);
|
||||
}
|
||||
|
||||
_methods = [moduleMethods copy];
|
||||
}
|
||||
return _methods;
|
||||
- (NSDictionary<NSString *, id<RCTBridgeMethod>> *)methodsByName
|
||||
{
|
||||
[self calculateMethods];
|
||||
return _methodsByName;
|
||||
}
|
||||
|
||||
- (void)gatherConstants
|
||||
|
|
|
@ -1060,7 +1060,7 @@ RCT_EXPORT_METHOD(findSubviewIn:(nonnull NSNumber *)reactTag atPoint:(CGPoint)po
|
|||
}
|
||||
|
||||
RCT_EXPORT_METHOD(dispatchViewManagerCommand:(nonnull NSNumber *)reactTag
|
||||
commandID:(NSInteger)commandID
|
||||
commandID:(id /*(NSString or NSNumber) */)commandID
|
||||
commandArgs:(NSArray<id> *)commandArgs)
|
||||
{
|
||||
RCTShadowView *shadowView = _shadowViewRegistry[reactTag];
|
||||
|
@ -1086,7 +1086,19 @@ RCT_EXPORT_METHOD(dispatchViewManagerCommand:(nonnull NSNumber *)reactTag
|
|||
|
||||
Class managerClass = componentData.managerClass;
|
||||
RCTModuleData *moduleData = [_bridge moduleDataForName:RCTBridgeModuleNameForClass(managerClass)];
|
||||
id<RCTBridgeMethod> method = moduleData.methods[commandID];
|
||||
|
||||
id<RCTBridgeMethod> method;
|
||||
if ([commandID isKindOfClass:[NSNumber class]]) {
|
||||
method = moduleData.methods[[commandID intValue]];
|
||||
} else if([commandID isKindOfClass:[NSString class]]) {
|
||||
method = moduleData.methodsByName[commandID];
|
||||
if (method == nil) {
|
||||
RCTLogError(@"No command found with name \"%@\"", commandID);
|
||||
}
|
||||
} else {
|
||||
RCTLogError(@"dispatchViewManagerCommand must be called with a string or integer command");
|
||||
return;
|
||||
}
|
||||
|
||||
NSArray *args = [@[reactTag] arrayByAddingObjectsFromArray:commandArgs];
|
||||
[method invokeWithBridge:_bridge module:componentData.manager arguments:args];
|
||||
|
|
Загрузка…
Ссылка в новой задаче