Skip to content

Commit deba13f

Browse files
committed
Refactor RCTUIManager
Summary: Moved the view creation & property binding logic out of RCTUIManager into a separate RCTComponentData class - this follows the pattern used with the bridge. I've also updated the property binding to use pre-allocated blocks for setting the values, which is more efficient than the previous system that re-contructed the selectors each time it was called. This should improve view update performance significantly.
1 parent aefdf82 commit deba13f

21 files changed

Lines changed: 514 additions & 494 deletions

Examples/UIExplorer/UIExplorerUnitTests/RCTSparseArrayTests.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ @implementation RCTSparseArrayTests
2525

2626
- (void)testDictionary
2727
{
28-
NSObject<RCTViewNodeProtocol> *myView = [[UIView alloc] init];
28+
id<RCTComponent> myView = [[UIView alloc] init];
2929
myView.reactTag = @4;
3030

31-
NSObject<RCTViewNodeProtocol> *myOtherView = [[UIView alloc] init];
31+
id<RCTComponent> myOtherView = [[UIView alloc] init];
3232
myOtherView.reactTag = @5;
3333

3434
RCTSparseArray *registry = [[RCTSparseArray alloc] init];

Libraries/ART/RCTConvert+ART.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ + (ARTCGFloatArray)ARTCGFloatArray:(id)json
144144
+ (ARTBrush *)ARTBrush:(id)json
145145
{
146146
NSArray *arr = [self NSArray:json];
147-
NSUInteger type = [self NSUInteger:arr[0]];
147+
NSUInteger type = [self NSUInteger:arr.firstObject];
148148
switch (type) {
149149
case 0: // solid color
150150
// These are probably expensive allocations since it's often the same value.

React/Base/RCTBridge.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,6 @@ RCT_EXTERN NSString *const RCTDidCreateNativeModules;
5454
*/
5555
typedef NSArray *(^RCTBridgeModuleProviderBlock)(void);
5656

57-
/**
58-
* Register the given class as a bridge module. All modules must be registered
59-
* prior to the first bridge initialization.
60-
*
61-
*/
62-
RCT_EXTERN void RCTRegisterModule(Class);
63-
6457
/**
6558
* This function returns the module name for a given class.
6659
*/
@@ -71,7 +64,6 @@ RCT_EXTERN NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass);
7164
*/
7265
@interface RCTBridge : NSObject <RCTInvalidating>
7366

74-
7567
/**
7668
* Creates a new bridge with a custom RCTBridgeDelegate.
7769
*

React/Base/RCTBridge.m

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ @interface RCTBridge ()
4848
return RCTModuleClasses;
4949
}
5050

51+
/**
52+
* Register the given class as a bridge module. All modules must be registered
53+
* prior to the first bridge initialization.
54+
*/
55+
void RCTRegisterModule(Class);
5156
void RCTRegisterModule(Class moduleClass)
5257
{
5358
static dispatch_once_t onceToken;
@@ -57,7 +62,7 @@ void RCTRegisterModule(Class moduleClass)
5762

5863
RCTAssert([moduleClass conformsToProtocol:@protocol(RCTBridgeModule)],
5964
@"%@ does not conform to the RCTBridgeModule protocol",
60-
NSStringFromClass(moduleClass));
65+
moduleClass);
6166

6267
// Register module
6368
[RCTModuleClasses addObject:moduleClass];

React/Base/RCTBridgeModule.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ extern dispatch_queue_t RCTJSThread;
9494
#define RCT_EXPORT_MODULE(js_name) \
9595
RCT_EXTERN void RCTRegisterModule(Class); \
9696
+ (NSString *)moduleName { return @#js_name; } \
97-
+ (void)load { RCTRegisterModule([self class]); }
97+
+ (void)load { RCTRegisterModule(self); }
9898

9999
/**
100100
* Wrap the parameter line of your method implementation with this macro to

React/Base/RCTConvert.h

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -136,21 +136,6 @@ typedef BOOL css_clip_t, css_backface_visibility_t;
136136

137137
@end
138138

139-
/**
140-
* This function will attempt to set a property using a json value by first
141-
* inferring the correct type from all available information, and then
142-
* applying an appropriate conversion method. If the property does not
143-
* exist, or the type cannot be inferred, the function will return NO.
144-
*/
145-
RCT_EXTERN BOOL RCTSetProperty(id target, NSString *keyPath, SEL type, id json);
146-
147-
/**
148-
* This function attempts to copy a property from the source object to the
149-
* destination object using KVC. If the property does not exist, or cannot
150-
* be set, it will do nothing and return NO.
151-
*/
152-
RCT_EXTERN BOOL RCTCopyProperty(id target, id source, NSString *keyPath);
153-
154139
/**
155140
* Underlying implementations of RCT_XXX_CONVERTER macros. Ignore these.
156141
*/

React/Base/RCTConvert.m

Lines changed: 0 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,177 +1056,3 @@ + (NSPropertyList)NSPropertyList:(id)json
10561056
}), RCTAnimationTypeEaseInEaseOut, integerValue)
10571057

10581058
@end
1059-
1060-
BOOL RCTSetProperty(id target, NSString *keyPath, SEL type, id json)
1061-
{
1062-
// Split keypath
1063-
NSArray *parts = [keyPath componentsSeparatedByString:@"."];
1064-
NSString *key = [parts lastObject];
1065-
for (NSUInteger i = 0; i < parts.count - 1; i++) {
1066-
target = [target valueForKey:parts[i]];
1067-
if (!target) {
1068-
return NO;
1069-
}
1070-
}
1071-
1072-
// Get property setter
1073-
SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:",
1074-
[[key substringToIndex:1] uppercaseString],
1075-
[key substringFromIndex:1]]);
1076-
1077-
// Fail early
1078-
if (![target respondsToSelector:setter]) {
1079-
return NO;
1080-
}
1081-
1082-
@try {
1083-
1084-
NSMethodSignature *signature = [RCTConvert methodSignatureForSelector:type];
1085-
switch (signature.methodReturnType[0]) {
1086-
1087-
#define RCT_SET_CASE(_value, _type) \
1088-
case _value: { \
1089-
_type (*convert)(id, SEL, id) = (typeof(convert))objc_msgSend; \
1090-
void (*set)(id, SEL, _type) = (typeof(set))objc_msgSend; \
1091-
set(target, setter, convert([RCTConvert class], type, json)); \
1092-
break; \
1093-
}
1094-
1095-
RCT_SET_CASE(':', SEL)
1096-
RCT_SET_CASE('*', const char *)
1097-
RCT_SET_CASE('c', char)
1098-
RCT_SET_CASE('C', unsigned char)
1099-
RCT_SET_CASE('s', short)
1100-
RCT_SET_CASE('S', unsigned short)
1101-
RCT_SET_CASE('i', int)
1102-
RCT_SET_CASE('I', unsigned int)
1103-
RCT_SET_CASE('l', long)
1104-
RCT_SET_CASE('L', unsigned long)
1105-
RCT_SET_CASE('q', long long)
1106-
RCT_SET_CASE('Q', unsigned long long)
1107-
RCT_SET_CASE('f', float)
1108-
RCT_SET_CASE('d', double)
1109-
RCT_SET_CASE('B', BOOL)
1110-
RCT_SET_CASE('^', void *)
1111-
1112-
case '@': {
1113-
id (*convert)(id, SEL, id) = (typeof(convert))objc_msgSend;
1114-
void (*set)(id, SEL, id) = (typeof(set))objc_msgSend;
1115-
set(target, setter, convert([RCTConvert class], type, json));
1116-
break;
1117-
}
1118-
case '{':
1119-
default: {
1120-
1121-
// Get converted value
1122-
void *value = malloc(signature.methodReturnLength);
1123-
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
1124-
[invocation setTarget:[RCTConvert class]];
1125-
[invocation setSelector:type];
1126-
[invocation setArgument:&json atIndex:2];
1127-
[invocation invoke];
1128-
[invocation getReturnValue:value];
1129-
1130-
// Set converted value
1131-
signature = [target methodSignatureForSelector:setter];
1132-
invocation = [NSInvocation invocationWithMethodSignature:signature];
1133-
[invocation setArgument:&setter atIndex:1];
1134-
[invocation setArgument:value atIndex:2];
1135-
[invocation invokeWithTarget:target];
1136-
free(value);
1137-
1138-
break;
1139-
}
1140-
}
1141-
return YES;
1142-
}
1143-
@catch (NSException *exception) {
1144-
RCTLogError(@"Exception thrown while attempting to set property '%@' of \
1145-
'%@' with value '%@': %@", key, [target class], json, exception);
1146-
return NO;
1147-
}
1148-
}
1149-
1150-
BOOL RCTCopyProperty(id target, id source, NSString *keyPath)
1151-
{
1152-
// Split keypath
1153-
NSArray *parts = [keyPath componentsSeparatedByString:@"."];
1154-
NSString *key = [parts lastObject];
1155-
for (NSUInteger i = 0; i < parts.count - 1; i++) {
1156-
source = [source valueForKey:parts[i]];
1157-
target = [target valueForKey:parts[i]];
1158-
if (!source || !target) {
1159-
return NO;
1160-
}
1161-
}
1162-
1163-
// Get property getter
1164-
SEL getter = NSSelectorFromString(key);
1165-
1166-
// Get property setter
1167-
SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:",
1168-
[[key substringToIndex:1] uppercaseString],
1169-
[key substringFromIndex:1]]);
1170-
1171-
// Fail early
1172-
if (![source respondsToSelector:getter] || ![target respondsToSelector:setter]) {
1173-
return NO;
1174-
}
1175-
1176-
NSMethodSignature *signature = [source methodSignatureForSelector:getter];
1177-
switch (signature.methodReturnType[0]) {
1178-
1179-
#define RCT_COPY_CASE(_value, _type) \
1180-
case _value: { \
1181-
_type (*get)(id, SEL) = (typeof(get))objc_msgSend; \
1182-
void (*set)(id, SEL, _type) = (typeof(set))objc_msgSend; \
1183-
set(target, setter, get(source, getter)); \
1184-
break; \
1185-
}
1186-
1187-
RCT_COPY_CASE(':', SEL)
1188-
RCT_COPY_CASE('*', const char *)
1189-
RCT_COPY_CASE('c', char)
1190-
RCT_COPY_CASE('C', unsigned char)
1191-
RCT_COPY_CASE('s', short)
1192-
RCT_COPY_CASE('S', unsigned short)
1193-
RCT_COPY_CASE('i', int)
1194-
RCT_COPY_CASE('I', unsigned int)
1195-
RCT_COPY_CASE('l', long)
1196-
RCT_COPY_CASE('L', unsigned long)
1197-
RCT_COPY_CASE('q', long long)
1198-
RCT_COPY_CASE('Q', unsigned long long)
1199-
RCT_COPY_CASE('f', float)
1200-
RCT_COPY_CASE('d', double)
1201-
RCT_COPY_CASE('B', BOOL)
1202-
RCT_COPY_CASE('^', void *)
1203-
1204-
case '@': {
1205-
id (*get)(id, SEL) = (typeof(get))objc_msgSend;
1206-
void (*set)(id, SEL, id) = (typeof(set))objc_msgSend;
1207-
set(target, setter, get(source, getter));
1208-
break;
1209-
}
1210-
case '{':
1211-
default: {
1212-
1213-
// Get value
1214-
void *value = malloc(signature.methodReturnLength);
1215-
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
1216-
[invocation setArgument:&getter atIndex:1];
1217-
[invocation invokeWithTarget:source];
1218-
[invocation getReturnValue:value];
1219-
1220-
// Set value
1221-
signature = [target methodSignatureForSelector:setter];
1222-
invocation = [NSInvocation invocationWithMethodSignature:signature];
1223-
[invocation setArgument:&setter atIndex:1];
1224-
[invocation setArgument:value atIndex:2];
1225-
[invocation invokeWithTarget:target];
1226-
free(value);
1227-
1228-
break;
1229-
}
1230-
}
1231-
return YES;
1232-
}

0 commit comments

Comments
 (0)