Break apart -[RCTComponentData propBlockForKey:inDictionary:]
Reviewed By: shergin Differential Revision: D4578549 fbshipit-source-id: 726773fdf8c97cdcc3b0540b32278e36c00b19b5
This commit is contained in:
parent
ebe3355de7
commit
bdd27f4696
|
@ -19,31 +19,13 @@
|
||||||
#import "UIView+React.h"
|
#import "UIView+React.h"
|
||||||
|
|
||||||
typedef void (^RCTPropBlock)(id<RCTComponent> view, id json);
|
typedef void (^RCTPropBlock)(id<RCTComponent> view, id json);
|
||||||
|
typedef NSMutableDictionary<NSString *, RCTPropBlock> RCTPropBlockDictionary;
|
||||||
@interface RCTComponentProp : NSObject
|
|
||||||
|
|
||||||
@property (nonatomic, copy, readonly) NSString *type;
|
|
||||||
@property (nonatomic, copy) RCTPropBlock propBlock;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation RCTComponentProp
|
|
||||||
|
|
||||||
- (instancetype)initWithType:(NSString *)type
|
|
||||||
{
|
|
||||||
if ((self = [super init])) {
|
|
||||||
_type = [type copy];
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation RCTComponentData
|
@implementation RCTComponentData
|
||||||
{
|
{
|
||||||
id<RCTComponent> _defaultView; // Only needed for RCT_CUSTOM_VIEW_PROPERTY
|
id<RCTComponent> _defaultView; // Only needed for RCT_CUSTOM_VIEW_PROPERTY
|
||||||
NSMutableDictionary<NSString *, RCTPropBlock> *_viewPropBlocks;
|
RCTPropBlockDictionary *_viewPropBlocks;
|
||||||
NSMutableDictionary<NSString *, RCTPropBlock> *_shadowPropBlocks;
|
RCTPropBlockDictionary *_shadowPropBlocks;
|
||||||
BOOL _implementsUIBlockToAmendWithShadowViewRegistry;
|
BOOL _implementsUIBlockToAmendWithShadowViewRegistry;
|
||||||
__weak RCTBridge *_bridge;
|
__weak RCTBridge *_bridge;
|
||||||
}
|
}
|
||||||
|
@ -120,244 +102,250 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
||||||
return shadowView;
|
return shadowView;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (RCTPropBlock)propBlockForKey:(NSString *)name
|
- (void)callCustomSetter:(SEL)setter onView:(id<RCTComponent>)view withProp:(id)json isShadowView:(BOOL)isShadowView
|
||||||
inDictionary:(NSMutableDictionary<NSString *, RCTPropBlock> *)propBlocks
|
|
||||||
{
|
{
|
||||||
BOOL shadowView = (propBlocks == _shadowPropBlocks);
|
json = RCTNilIfNull(json);
|
||||||
RCTPropBlock propBlock = propBlocks[name];
|
if (!isShadowView) {
|
||||||
if (!propBlock) {
|
if (!json && !_defaultView) {
|
||||||
|
// Only create default view if json is null
|
||||||
__weak RCTComponentData *weakSelf = self;
|
_defaultView = [self createViewWithTag:nil];
|
||||||
|
|
||||||
// Get type
|
|
||||||
SEL type = NULL;
|
|
||||||
NSString *keyPath = nil;
|
|
||||||
SEL selector = NSSelectorFromString([NSString stringWithFormat:@"propConfig%@_%@", shadowView ? @"Shadow" : @"", name]);
|
|
||||||
if ([_managerClass respondsToSelector:selector]) {
|
|
||||||
NSArray<NSString *> *typeAndKeyPath =
|
|
||||||
((NSArray<NSString *> *(*)(id, SEL))objc_msgSend)(_managerClass, selector);
|
|
||||||
type = RCTConvertSelectorForType(typeAndKeyPath[0]);
|
|
||||||
keyPath = typeAndKeyPath.count > 1 ? typeAndKeyPath[1] : nil;
|
|
||||||
} else {
|
|
||||||
propBlock = ^(__unused id view, __unused id json) {};
|
|
||||||
propBlocks[name] = propBlock;
|
|
||||||
return propBlock;
|
|
||||||
}
|
}
|
||||||
|
((void (*)(id, SEL, id, id, id))objc_msgSend)(self.manager, setter, json, view, _defaultView);
|
||||||
|
} else {
|
||||||
|
((void (*)(id, SEL, id, id))objc_msgSend)(self.manager, setter, json, view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check for custom setter
|
static RCTPropBlock createEventSetter(NSString *propName, SEL setter, RCTBridge *bridge)
|
||||||
if ([keyPath isEqualToString:@"__custom__"]) {
|
{
|
||||||
|
__weak RCTBridge *weakBridge = bridge;
|
||||||
// Get custom setter. There is no default view in the shadow case, so the selector is different.
|
return ^(id target, id json) {
|
||||||
NSString *selectorString;
|
void (^eventHandler)(NSDictionary *event) = nil;
|
||||||
if (!shadowView) {
|
if ([RCTConvert BOOL:json]) {
|
||||||
selectorString = [NSString stringWithFormat:@"set_%@:for%@View:withDefaultView:", name, shadowView ? @"Shadow" : @""];
|
__weak id<RCTComponent> weakTarget = target;
|
||||||
} else {
|
eventHandler = ^(NSDictionary *event) {
|
||||||
selectorString = [NSString stringWithFormat:@"set_%@:forShadowView:", name];
|
// The component no longer exists, we shouldn't send the event
|
||||||
}
|
id<RCTComponent> strongTarget = weakTarget;
|
||||||
SEL customSetter = NSSelectorFromString(selectorString);
|
if (!strongTarget) {
|
||||||
|
|
||||||
propBlock = ^(id<RCTComponent> view, id json) {
|
|
||||||
RCTComponentData *strongSelf = weakSelf;
|
|
||||||
if (!strongSelf) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
json = RCTNilIfNull(json);
|
|
||||||
if (!shadowView) {
|
|
||||||
if (!json && !strongSelf->_defaultView) {
|
|
||||||
// Only create default view if json is null
|
|
||||||
strongSelf->_defaultView = [strongSelf createViewWithTag:nil];
|
|
||||||
}
|
|
||||||
((void (*)(id, SEL, id, id, id))objc_msgSend)(
|
|
||||||
strongSelf.manager, customSetter, json, view, strongSelf->_defaultView
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
((void (*)(id, SEL, id, id))objc_msgSend)(
|
|
||||||
strongSelf.manager, customSetter, json, view
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} else {
|
NSMutableDictionary *mutableEvent = [NSMutableDictionary dictionaryWithDictionary:event];
|
||||||
|
mutableEvent[@"target"] = strongTarget.reactTag;
|
||||||
// Disect keypath
|
|
||||||
NSString *key = name;
|
|
||||||
NSArray<NSString *> *parts = [keyPath componentsSeparatedByString:@"."];
|
|
||||||
if (parts) {
|
|
||||||
key = parts.lastObject;
|
|
||||||
parts = [parts subarrayWithRange:(NSRange){0, parts.count - 1}];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get property getter
|
|
||||||
SEL getter = NSSelectorFromString(key);
|
|
||||||
|
|
||||||
// Get property setter
|
|
||||||
SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:",
|
|
||||||
[key substringToIndex:1].uppercaseString,
|
|
||||||
[key substringFromIndex:1]]);
|
|
||||||
|
|
||||||
// Build setter block
|
|
||||||
void (^setterBlock)(id target, id json) = nil;
|
|
||||||
if (type == NSSelectorFromString(@"RCTBubblingEventBlock:") ||
|
|
||||||
type == NSSelectorFromString(@"RCTDirectEventBlock:")) {
|
|
||||||
|
|
||||||
// Special case for event handlers
|
|
||||||
__weak RCTViewManager *weakManager = self.manager;
|
|
||||||
setterBlock = ^(id target, id json) {
|
|
||||||
__weak id<RCTComponent> weakTarget = target;
|
|
||||||
((void (*)(id, SEL, id))objc_msgSend)(target, setter, [RCTConvert BOOL:json] ? ^(NSDictionary *body) {
|
|
||||||
body = [NSMutableDictionary dictionaryWithDictionary:body];
|
|
||||||
((NSMutableDictionary *)body)[@"target"] = weakTarget.reactTag;
|
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||||
[weakManager.bridge.eventDispatcher sendInputEventWithName:RCTNormalizeInputEventName(name) body:body];
|
[weakBridge.eventDispatcher sendInputEventWithName:RCTNormalizeInputEventName(propName) body:mutableEvent];
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
} : nil);
|
};
|
||||||
};
|
}
|
||||||
|
((void (*)(id, SEL, id))objc_msgSend)(target, setter, eventHandler);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
static RCTPropBlock createNSInvocationSetter(NSMethodSignature *typeSignature, SEL type, SEL getter, SEL setter)
|
||||||
|
{
|
||||||
|
NSInvocation *typeInvocation = [NSInvocation invocationWithMethodSignature:typeSignature];
|
||||||
|
typeInvocation.selector = type;
|
||||||
|
typeInvocation.target = [RCTConvert class];
|
||||||
|
|
||||||
// Ordinary property handlers
|
__block NSInvocation *targetInvocation = nil;
|
||||||
NSMethodSignature *typeSignature = [[RCTConvert class] methodSignatureForSelector:type];
|
__block NSMutableData *defaultValue = nil;
|
||||||
if (!typeSignature) {
|
|
||||||
RCTLogError(@"No +[RCTConvert %@] function found.", NSStringFromSelector(type));
|
|
||||||
return ^(__unused id<RCTComponent> view, __unused id json){};
|
|
||||||
}
|
|
||||||
switch (typeSignature.methodReturnType[0]) {
|
|
||||||
|
|
||||||
#define RCT_CASE(_value, _type) \
|
return ^(id target, id json) {
|
||||||
case _value: { \
|
if (!target) {
|
||||||
__block BOOL setDefaultValue = NO; \
|
return;
|
||||||
__block _type defaultValue; \
|
}
|
||||||
_type (*convert)(id, SEL, id) = (typeof(convert))objc_msgSend; \
|
|
||||||
_type (*get)(id, SEL) = (typeof(get))objc_msgSend; \
|
|
||||||
void (*set)(id, SEL, _type) = (typeof(set))objc_msgSend; \
|
|
||||||
setterBlock = ^(id target, id json) { \
|
|
||||||
if (json) { \
|
|
||||||
if (!setDefaultValue && target) { \
|
|
||||||
if ([target respondsToSelector:getter]) { \
|
|
||||||
defaultValue = get(target, getter); \
|
|
||||||
} \
|
|
||||||
setDefaultValue = YES; \
|
|
||||||
} \
|
|
||||||
set(target, setter, convert([RCTConvert class], type, json)); \
|
|
||||||
} else if (setDefaultValue) { \
|
|
||||||
set(target, setter, defaultValue); \
|
|
||||||
} \
|
|
||||||
}; \
|
|
||||||
break; \
|
|
||||||
}
|
|
||||||
|
|
||||||
RCT_CASE(_C_SEL, SEL)
|
// Get default value
|
||||||
RCT_CASE(_C_CHARPTR, const char *)
|
if (!defaultValue) {
|
||||||
RCT_CASE(_C_CHR, char)
|
if (!json) {
|
||||||
RCT_CASE(_C_UCHR, unsigned char)
|
// We only set the defaultValue when we first pass a non-null
|
||||||
RCT_CASE(_C_SHT, short)
|
// value, so if the first value sent for a prop is null, it's
|
||||||
RCT_CASE(_C_USHT, unsigned short)
|
// a no-op (we'd be resetting it to its default when its
|
||||||
RCT_CASE(_C_INT, int)
|
// value is already the default).
|
||||||
RCT_CASE(_C_UINT, unsigned int)
|
return;
|
||||||
RCT_CASE(_C_LNG, long)
|
}
|
||||||
RCT_CASE(_C_ULNG, unsigned long)
|
// Use NSMutableData to store defaultValue instead of malloc, so
|
||||||
RCT_CASE(_C_LNG_LNG, long long)
|
// it will be freed automatically when setterBlock is released.
|
||||||
RCT_CASE(_C_ULNG_LNG, unsigned long long)
|
defaultValue = [[NSMutableData alloc] initWithLength:typeSignature.methodReturnLength];
|
||||||
RCT_CASE(_C_FLT, float)
|
if ([target respondsToSelector:getter]) {
|
||||||
RCT_CASE(_C_DBL, double)
|
NSMethodSignature *signature = [target methodSignatureForSelector:getter];
|
||||||
RCT_CASE(_C_BOOL, BOOL)
|
NSInvocation *sourceInvocation = [NSInvocation invocationWithMethodSignature:signature];
|
||||||
RCT_CASE(_C_PTR, void *)
|
sourceInvocation.selector = getter;
|
||||||
RCT_CASE(_C_ID, id)
|
[sourceInvocation invokeWithTarget:target];
|
||||||
|
[sourceInvocation getReturnValue:defaultValue.mutableBytes];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case _C_STRUCT_B:
|
// Get value
|
||||||
default: {
|
BOOL freeValueOnCompletion = NO;
|
||||||
|
void *value = defaultValue.mutableBytes;
|
||||||
|
if (json) {
|
||||||
|
freeValueOnCompletion = YES;
|
||||||
|
value = malloc(typeSignature.methodReturnLength);
|
||||||
|
[typeInvocation setArgument:&json atIndex:2];
|
||||||
|
[typeInvocation invoke];
|
||||||
|
[typeInvocation getReturnValue:value];
|
||||||
|
}
|
||||||
|
|
||||||
NSInvocation *typeInvocation = [NSInvocation invocationWithMethodSignature:typeSignature];
|
// Set value
|
||||||
typeInvocation.selector = type;
|
if (!targetInvocation) {
|
||||||
typeInvocation.target = [RCTConvert class];
|
NSMethodSignature *signature = [target methodSignatureForSelector:setter];
|
||||||
|
targetInvocation = [NSInvocation invocationWithMethodSignature:signature];
|
||||||
|
targetInvocation.selector = setter;
|
||||||
|
}
|
||||||
|
[targetInvocation setArgument:value atIndex:2];
|
||||||
|
[targetInvocation invokeWithTarget:target];
|
||||||
|
if (freeValueOnCompletion) {
|
||||||
|
// Only free the value if we `malloc`d it locally, otherwise it
|
||||||
|
// points to `defaultValue.mutableBytes`, which is managed by ARC.
|
||||||
|
free(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
__block NSInvocation *targetInvocation = nil;
|
- (RCTPropBlock)createPropBlock:(NSString *)name isShadowView:(BOOL)isShadowView
|
||||||
__block NSMutableData *defaultValue = nil;
|
{
|
||||||
|
// Get type
|
||||||
|
SEL type = NULL;
|
||||||
|
NSString *keyPath = nil;
|
||||||
|
SEL selector = NSSelectorFromString([NSString stringWithFormat:@"propConfig%@_%@", isShadowView ? @"Shadow" : @"", name]);
|
||||||
|
if ([_managerClass respondsToSelector:selector]) {
|
||||||
|
NSArray<NSString *> *typeAndKeyPath = ((NSArray<NSString *> *(*)(id, SEL))objc_msgSend)(_managerClass, selector);
|
||||||
|
type = RCTConvertSelectorForType(typeAndKeyPath[0]);
|
||||||
|
keyPath = typeAndKeyPath.count > 1 ? typeAndKeyPath[1] : nil;
|
||||||
|
} else {
|
||||||
|
return ^(__unused id view, __unused id json) {};
|
||||||
|
}
|
||||||
|
|
||||||
setterBlock = ^(id target, id json) { \
|
// Check for custom setter
|
||||||
|
if ([keyPath isEqualToString:@"__custom__"]) {
|
||||||
|
// Get custom setter. There is no default view in the shadow case, so the selector is different.
|
||||||
|
NSString *selectorString;
|
||||||
|
if (!isShadowView) {
|
||||||
|
selectorString = [NSString stringWithFormat:@"set_%@:for%@View:withDefaultView:", name, isShadowView ? @"Shadow" : @""];
|
||||||
|
} else {
|
||||||
|
selectorString = [NSString stringWithFormat:@"set_%@:forShadowView:", name];
|
||||||
|
}
|
||||||
|
|
||||||
if (!target) {
|
SEL customSetter = NSSelectorFromString(selectorString);
|
||||||
return;
|
__weak RCTComponentData *weakSelf = self;
|
||||||
}
|
return ^(id<RCTComponent> view, id json) {
|
||||||
|
[weakSelf callCustomSetter:customSetter onView:view withProp:json isShadowView:isShadowView];
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// Disect keypath
|
||||||
|
NSString *key = name;
|
||||||
|
NSArray<NSString *> *parts = [keyPath componentsSeparatedByString:@"."];
|
||||||
|
if (parts) {
|
||||||
|
key = parts.lastObject;
|
||||||
|
parts = [parts subarrayWithRange:(NSRange){0, parts.count - 1}];
|
||||||
|
}
|
||||||
|
|
||||||
// Get default value
|
// Get property getter
|
||||||
if (!defaultValue) {
|
SEL getter = NSSelectorFromString(key);
|
||||||
if (!json) {
|
|
||||||
// We only set the defaultValue when we first pass a non-null
|
|
||||||
// value, so if the first value sent for a prop is null, it's
|
|
||||||
// a no-op (we'd be resetting it to its default when its
|
|
||||||
// value is already the default).
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Use NSMutableData to store defaultValue instead of malloc, so
|
|
||||||
// it will be freed automatically when setterBlock is released.
|
|
||||||
defaultValue = [[NSMutableData alloc] initWithLength:typeSignature.methodReturnLength];
|
|
||||||
if ([target respondsToSelector:getter]) {
|
|
||||||
NSMethodSignature *signature = [target methodSignatureForSelector:getter];
|
|
||||||
NSInvocation *sourceInvocation = [NSInvocation invocationWithMethodSignature:signature];
|
|
||||||
sourceInvocation.selector = getter;
|
|
||||||
[sourceInvocation invokeWithTarget:target];
|
|
||||||
[sourceInvocation getReturnValue:defaultValue.mutableBytes];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get value
|
// Get property setter
|
||||||
BOOL freeValueOnCompletion = NO;
|
SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:",
|
||||||
void *value = defaultValue.mutableBytes;
|
[key substringToIndex:1].uppercaseString,
|
||||||
if (json) {
|
[key substringFromIndex:1]]);
|
||||||
freeValueOnCompletion = YES;
|
|
||||||
value = malloc(typeSignature.methodReturnLength);
|
|
||||||
[typeInvocation setArgument:&json atIndex:2];
|
|
||||||
[typeInvocation invoke];
|
|
||||||
[typeInvocation getReturnValue:value];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set value
|
// Build setter block
|
||||||
if (!targetInvocation) {
|
void (^setterBlock)(id target, id json) = nil;
|
||||||
NSMethodSignature *signature = [target methodSignatureForSelector:setter];
|
if (type == NSSelectorFromString(@"RCTBubblingEventBlock:") ||
|
||||||
targetInvocation = [NSInvocation invocationWithMethodSignature:signature];
|
type == NSSelectorFromString(@"RCTDirectEventBlock:")) {
|
||||||
targetInvocation.selector = setter;
|
// Special case for event handlers
|
||||||
}
|
setterBlock = createEventSetter(name, setter, _bridge);
|
||||||
[targetInvocation setArgument:value atIndex:2];
|
} else {
|
||||||
[targetInvocation invokeWithTarget:target];
|
// Ordinary property handlers
|
||||||
if (freeValueOnCompletion) {
|
NSMethodSignature *typeSignature = [[RCTConvert class] methodSignatureForSelector:type];
|
||||||
// Only free the value if we `malloc`d it locally, otherwise it
|
if (!typeSignature) {
|
||||||
// points to `defaultValue.mutableBytes`, which is managed by ARC.
|
RCTLogError(@"No +[RCTConvert %@] function found.", NSStringFromSelector(type));
|
||||||
free(value);
|
return ^(__unused id<RCTComponent> view, __unused id json){};
|
||||||
}
|
}
|
||||||
};
|
switch (typeSignature.methodReturnType[0]) {
|
||||||
break;
|
|
||||||
}
|
#define RCT_CASE(_value, _type) \
|
||||||
|
case _value: { \
|
||||||
|
__block BOOL setDefaultValue = NO; \
|
||||||
|
__block _type defaultValue; \
|
||||||
|
_type (*convert)(id, SEL, id) = (typeof(convert))objc_msgSend; \
|
||||||
|
_type (*get)(id, SEL) = (typeof(get))objc_msgSend; \
|
||||||
|
void (*set)(id, SEL, _type) = (typeof(set))objc_msgSend; \
|
||||||
|
setterBlock = ^(id target, id json) { \
|
||||||
|
if (json) { \
|
||||||
|
if (!setDefaultValue && target) { \
|
||||||
|
if ([target respondsToSelector:getter]) { \
|
||||||
|
defaultValue = get(target, getter); \
|
||||||
|
} \
|
||||||
|
setDefaultValue = YES; \
|
||||||
|
} \
|
||||||
|
set(target, setter, convert([RCTConvert class], type, json)); \
|
||||||
|
} else if (setDefaultValue) { \
|
||||||
|
set(target, setter, defaultValue); \
|
||||||
|
} \
|
||||||
|
}; \
|
||||||
|
break; \
|
||||||
|
}
|
||||||
|
|
||||||
|
RCT_CASE(_C_SEL, SEL)
|
||||||
|
RCT_CASE(_C_CHARPTR, const char *)
|
||||||
|
RCT_CASE(_C_CHR, char)
|
||||||
|
RCT_CASE(_C_UCHR, unsigned char)
|
||||||
|
RCT_CASE(_C_SHT, short)
|
||||||
|
RCT_CASE(_C_USHT, unsigned short)
|
||||||
|
RCT_CASE(_C_INT, int)
|
||||||
|
RCT_CASE(_C_UINT, unsigned int)
|
||||||
|
RCT_CASE(_C_LNG, long)
|
||||||
|
RCT_CASE(_C_ULNG, unsigned long)
|
||||||
|
RCT_CASE(_C_LNG_LNG, long long)
|
||||||
|
RCT_CASE(_C_ULNG_LNG, unsigned long long)
|
||||||
|
RCT_CASE(_C_FLT, float)
|
||||||
|
RCT_CASE(_C_DBL, double)
|
||||||
|
RCT_CASE(_C_BOOL, BOOL)
|
||||||
|
RCT_CASE(_C_PTR, void *)
|
||||||
|
RCT_CASE(_C_ID, id)
|
||||||
|
|
||||||
|
case _C_STRUCT_B:
|
||||||
|
default: {
|
||||||
|
setterBlock = createNSInvocationSetter(typeSignature, type, getter, setter);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
propBlock = ^(__unused id view, __unused id json) {
|
|
||||||
|
|
||||||
// Follow keypath
|
|
||||||
id target = view;
|
|
||||||
for (NSString *part in parts) {
|
|
||||||
target = [target valueForKey:part];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set property with json
|
|
||||||
setterBlock(target, RCTNilIfNull(json));
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RCT_DEBUG) {
|
return ^(__unused id view, __unused id json) {
|
||||||
|
// Follow keypath
|
||||||
|
id target = view;
|
||||||
|
for (NSString *part in parts) {
|
||||||
|
target = [target valueForKey:part];
|
||||||
|
}
|
||||||
|
|
||||||
// Provide more useful log feedback if there's an error
|
// Set property with json
|
||||||
RCTPropBlock unwrappedBlock = propBlock;
|
setterBlock(target, RCTNilIfNull(json));
|
||||||
propBlock = ^(id<RCTComponent> view, id json) {
|
};
|
||||||
NSString *logPrefix = [NSString stringWithFormat:
|
}
|
||||||
@"Error setting property '%@' of %@ with tag #%@: ",
|
}
|
||||||
name, weakSelf.name, view.reactTag];
|
|
||||||
|
|
||||||
RCTPerformBlockWithLogPrefix(^{ unwrappedBlock(view, json); }, logPrefix);
|
- (RCTPropBlock)propBlockForKey:(NSString *)name isShadowView:(BOOL)isShadowView
|
||||||
};
|
{
|
||||||
}
|
RCTPropBlockDictionary *propBlocks = isShadowView ? _shadowPropBlocks : _viewPropBlocks;
|
||||||
|
RCTPropBlock propBlock = propBlocks[name];
|
||||||
|
if (!propBlock) {
|
||||||
|
propBlock = [self createPropBlock:name isShadowView:isShadowView];
|
||||||
|
|
||||||
|
#if RCT_DEBUG
|
||||||
|
// Provide more useful log feedback if there's an error
|
||||||
|
RCTPropBlock unwrappedBlock = propBlock;
|
||||||
|
__weak __typeof(self) weakSelf = self;
|
||||||
|
propBlock = ^(id<RCTComponent> view, id json) {
|
||||||
|
NSString *logPrefix = [NSString stringWithFormat:@"Error setting property '%@' of %@ with tag #%@: ",
|
||||||
|
name, weakSelf.name, view.reactTag];
|
||||||
|
RCTPerformBlockWithLogPrefix(^{
|
||||||
|
unwrappedBlock(view, json);
|
||||||
|
}, logPrefix);
|
||||||
|
};
|
||||||
|
#endif
|
||||||
propBlocks[name] = [propBlock copy];
|
propBlocks[name] = [propBlock copy];
|
||||||
}
|
}
|
||||||
return propBlock;
|
return propBlock;
|
||||||
|
@ -370,7 +358,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
||||||
}
|
}
|
||||||
|
|
||||||
[props enumerateKeysAndObjectsUsingBlock:^(NSString *key, id json, __unused BOOL *stop) {
|
[props enumerateKeysAndObjectsUsingBlock:^(NSString *key, id json, __unused BOOL *stop) {
|
||||||
[self propBlockForKey:key inDictionary:self->_viewPropBlocks](view, json);
|
[self propBlockForKey:key isShadowView:NO](view, json);
|
||||||
}];
|
}];
|
||||||
|
|
||||||
if ([view respondsToSelector:@selector(didSetProps:)]) {
|
if ([view respondsToSelector:@selector(didSetProps:)]) {
|
||||||
|
@ -385,7 +373,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
||||||
}
|
}
|
||||||
|
|
||||||
[props enumerateKeysAndObjectsUsingBlock:^(NSString *key, id json, __unused BOOL *stop) {
|
[props enumerateKeysAndObjectsUsingBlock:^(NSString *key, id json, __unused BOOL *stop) {
|
||||||
[self propBlockForKey:key inDictionary:self->_shadowPropBlocks](shadowView, json);
|
[self propBlockForKey:key isShadowView:YES](shadowView, json);
|
||||||
}];
|
}];
|
||||||
|
|
||||||
if ([shadowView respondsToSelector:@selector(didSetProps:)]) {
|
if ([shadowView respondsToSelector:@selector(didSetProps:)]) {
|
||||||
|
|
Loading…
Reference in New Issue