Refactored RCTLog and added facility to prepend extra data to the log message
This commit is contained in:
parent
5b3e935332
commit
80cd687e95
|
@ -1,5 +1,9 @@
|
||||||
{
|
{
|
||||||
"images" : [
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "2x",
|
"scale" : "2x",
|
||||||
|
|
|
@ -71,7 +71,7 @@
|
||||||
|
|
||||||
UIView *view = viewRegistry[reactTag];
|
UIView *view = viewRegistry[reactTag];
|
||||||
if (!view) {
|
if (!view) {
|
||||||
RCTLogWarn(@"React tag %@ is not registered with the view registry", reactTag);
|
RCTLogWarn(@"React tag #%@ is not registered with the view registry", reactTag);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,9 @@ typedef void (^WSMessageCallback)(NSError *error, NSDictionary *reply);
|
||||||
|
|
||||||
[_jsQueue addOperationWithBlock:^{
|
[_jsQueue addOperationWithBlock:^{
|
||||||
if (!self.valid) {
|
if (!self.valid) {
|
||||||
NSError *error = [NSError errorWithDomain:@"WS" code:1 userInfo:@{NSLocalizedDescriptionKey:@"socket closed"}];
|
NSError *error = [NSError errorWithDomain:@"WS" code:1 userInfo:@{
|
||||||
|
NSLocalizedDescriptionKey: @"socket closed"
|
||||||
|
}];
|
||||||
callback(error, nil);
|
callback(error, nil);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,11 @@ typedef NSArray *(^RCTBridgeModuleProviderBlock)(void);
|
||||||
|
|
||||||
extern NSString *const RCTReloadBridge;
|
extern NSString *const RCTReloadBridge;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns the module name for a given class.
|
||||||
|
*/
|
||||||
|
extern NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Async batched bridge used to communicate with the JavaScript application.
|
* Async batched bridge used to communicate with the JavaScript application.
|
||||||
*/
|
*/
|
||||||
|
@ -81,14 +86,6 @@ extern NSString *const RCTReloadBridge;
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, readonly) dispatch_queue_t shadowQueue;
|
@property (nonatomic, readonly) dispatch_queue_t shadowQueue;
|
||||||
|
|
||||||
/**
|
|
||||||
* Global logging function that will print to both xcode and JS debugger consoles.
|
|
||||||
*
|
|
||||||
* NOTE: Use via RCTLog* macros defined in RCTLog.h
|
|
||||||
* TODO (#5906496): should log function be exposed here, or could it be a module?
|
|
||||||
*/
|
|
||||||
+ (void)log:(NSArray *)objects level:(NSString *)level;
|
|
||||||
|
|
||||||
@property (nonatomic, copy, readonly) NSDictionary *launchOptions;
|
@property (nonatomic, copy, readonly) NSDictionary *launchOptions;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#import "RCTJavaScriptLoader.h"
|
#import "RCTJavaScriptLoader.h"
|
||||||
#import "RCTKeyCommands.h"
|
#import "RCTKeyCommands.h"
|
||||||
#import "RCTLog.h"
|
#import "RCTLog.h"
|
||||||
|
#import "RCTRedBox.h"
|
||||||
#import "RCTRootView.h"
|
#import "RCTRootView.h"
|
||||||
#import "RCTSparseArray.h"
|
#import "RCTSparseArray.h"
|
||||||
#import "RCTUtils.h"
|
#import "RCTUtils.h"
|
||||||
|
@ -41,10 +42,7 @@ typedef NS_ENUM(NSUInteger, RCTBridgeFields) {
|
||||||
|
|
||||||
NSString *const RCTReloadBridge = @"RCTReloadBridge";
|
NSString *const RCTReloadBridge = @"RCTReloadBridge";
|
||||||
|
|
||||||
/**
|
NSString *RCTBridgeModuleNameForClass(Class cls)
|
||||||
* This function returns the module name for a given class.
|
|
||||||
*/
|
|
||||||
static NSString *RCTModuleNameForClass(Class cls)
|
|
||||||
{
|
{
|
||||||
return [cls respondsToSelector:@selector(moduleName)] ? [cls moduleName] : NSStringFromClass(cls);
|
return [cls respondsToSelector:@selector(moduleName)] ? [cls moduleName] : NSStringFromClass(cls);
|
||||||
}
|
}
|
||||||
|
@ -92,7 +90,7 @@ static NSArray *RCTBridgeModuleClassesByModuleID(void)
|
||||||
[(NSMutableArray *)modules addObject:cls];
|
[(NSMutableArray *)modules addObject:cls];
|
||||||
|
|
||||||
// Add module name
|
// Add module name
|
||||||
NSString *moduleName = RCTModuleNameForClass(cls);
|
NSString *moduleName = RCTBridgeModuleNameForClass(cls);
|
||||||
[(NSMutableArray *)RCTModuleNamesByID addObject:moduleName];
|
[(NSMutableArray *)RCTModuleNamesByID addObject:moduleName];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -187,7 +185,7 @@ static Class _globalExecutorClass;
|
||||||
RCT_ARG_BLOCK( \
|
RCT_ARG_BLOCK( \
|
||||||
if (json && ![json isKindOfClass:[_class class]]) { \
|
if (json && ![json isKindOfClass:[_class class]]) { \
|
||||||
RCTLogError(@"Argument %tu (%@) of %@.%@ should be of type %@", index, \
|
RCTLogError(@"Argument %tu (%@) of %@.%@ should be of type %@", index, \
|
||||||
json, RCTModuleNameForClass(_moduleClass), _JSMethodName, [_class class]); \
|
json, RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName, [_class class]); \
|
||||||
return; \
|
return; \
|
||||||
} \
|
} \
|
||||||
_logic \
|
_logic \
|
||||||
|
@ -203,7 +201,7 @@ static Class _globalExecutorClass;
|
||||||
RCT_ARG_BLOCK( \
|
RCT_ARG_BLOCK( \
|
||||||
if (json && ![json respondsToSelector:@selector(_selector)]) { \
|
if (json && ![json respondsToSelector:@selector(_selector)]) { \
|
||||||
RCTLogError(@"Argument %tu (%@) of %@.%@ does not respond to selector: %@", \
|
RCTLogError(@"Argument %tu (%@) of %@.%@ does not respond to selector: %@", \
|
||||||
index, json, RCTModuleNameForClass(_moduleClass), _JSMethodName, @#_selector); \
|
index, json, RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName, @#_selector); \
|
||||||
return; \
|
return; \
|
||||||
} \
|
} \
|
||||||
_type value = [json _selector]; \
|
_type value = [json _selector]; \
|
||||||
|
@ -231,7 +229,7 @@ static Class _globalExecutorClass;
|
||||||
RCT_ARG_BLOCK(
|
RCT_ARG_BLOCK(
|
||||||
if (json && ![json isKindOfClass:[NSNumber class]]) {
|
if (json && ![json isKindOfClass:[NSNumber class]]) {
|
||||||
RCTLogError(@"Argument %tu (%@) of %@.%@ should be a number", index,
|
RCTLogError(@"Argument %tu (%@) of %@.%@ should be a number", index,
|
||||||
json, RCTModuleNameForClass(_moduleClass), _JSMethodName);
|
json, RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Marked as autoreleasing, because NSInvocation doesn't retain arguments
|
// Marked as autoreleasing, because NSInvocation doesn't retain arguments
|
||||||
|
@ -268,7 +266,7 @@ static Class _globalExecutorClass;
|
||||||
// Safety check
|
// Safety check
|
||||||
if (arguments.count != _argumentBlocks.count) {
|
if (arguments.count != _argumentBlocks.count) {
|
||||||
RCTLogError(@"%@.%@ was called with %zd arguments, but expects %zd",
|
RCTLogError(@"%@.%@ was called with %zd arguments, but expects %zd",
|
||||||
RCTModuleNameForClass(_moduleClass), _JSMethodName,
|
RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName,
|
||||||
arguments.count, _argumentBlocks.count);
|
arguments.count, _argumentBlocks.count);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -544,7 +542,7 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
||||||
// Register passed-in module instances
|
// Register passed-in module instances
|
||||||
NSMutableDictionary *preregisteredModules = [[NSMutableDictionary alloc] init];
|
NSMutableDictionary *preregisteredModules = [[NSMutableDictionary alloc] init];
|
||||||
for (id<RCTBridgeModule> module in _moduleProvider ? _moduleProvider() : nil) {
|
for (id<RCTBridgeModule> module in _moduleProvider ? _moduleProvider() : nil) {
|
||||||
preregisteredModules[RCTModuleNameForClass([module class])] = module;
|
preregisteredModules[RCTBridgeModuleNameForClass([module class])] = module;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instantiate modules
|
// Instantiate modules
|
||||||
|
@ -895,27 +893,18 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
||||||
return (_latestJSExecutor != nil && [_latestJSExecutor isValid]);
|
return (_latestJSExecutor != nil && [_latestJSExecutor isValid]);
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)log:(NSArray *)objects level:(NSString *)level
|
+ (void)logMessage:(NSString *)message level:(NSString *)level
|
||||||
{
|
{
|
||||||
if (!_latestJSExecutor || ![_latestJSExecutor isValid]) {
|
if (!_latestJSExecutor || ![_latestJSExecutor isValid]) {
|
||||||
RCTLogError(@"ERROR: No valid JS executor to log %@.", objects);
|
RCTLogError(@"ERROR: No valid JS executor to log '%@'.", message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
NSMutableArray *args = [NSMutableArray arrayWithObject:level];
|
|
||||||
|
|
||||||
// TODO (#5906496): Find out and document why we skip the first object
|
// Note: the js executor could get invalidated while we're trying to call
|
||||||
for (id ob in [objects subarrayWithRange:(NSRange){1, [objects count] - 1}]) {
|
// this...need to watch out for that.
|
||||||
if ([NSJSONSerialization isValidJSONObject:@[ob]]) {
|
|
||||||
[args addObject:ob];
|
|
||||||
} else {
|
|
||||||
[args addObject:[ob description]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: the js executor could get invalidated while we're trying to call this...need to watch out for that.
|
|
||||||
[_latestJSExecutor executeJSCall:@"RCTLog"
|
[_latestJSExecutor executeJSCall:@"RCTLog"
|
||||||
method:@"logIfNoNativeHook"
|
method:@"logIfNoNativeHook"
|
||||||
arguments:args
|
arguments:@[level, message]
|
||||||
callback:^(id json, NSError *error) {}];
|
callback:^(id json, NSError *error) {}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -145,7 +145,7 @@ RCT_CUSTOM_CONVERTER(type, name, [json getter])
|
||||||
} \
|
} \
|
||||||
@catch (__unused NSException *e) { \
|
@catch (__unused NSException *e) { \
|
||||||
RCTLogError(@"JSON value '%@' of type '%@' cannot be converted to '%s'", \
|
RCTLogError(@"JSON value '%@' of type '%@' cannot be converted to '%s'", \
|
||||||
json, [json class], #type); \
|
json, [json classForCoder], #type); \
|
||||||
json = nil; \
|
json = nil; \
|
||||||
return code; \
|
return code; \
|
||||||
} \
|
} \
|
||||||
|
@ -181,7 +181,8 @@ RCT_CUSTOM_CONVERTER(type, type, [[self NSNumber:json] getter])
|
||||||
return default; \
|
return default; \
|
||||||
} \
|
} \
|
||||||
if (![json isKindOfClass:[NSString class]]) { \
|
if (![json isKindOfClass:[NSString class]]) { \
|
||||||
RCTLogError(@"Expected NSNumber or NSString for %s, received %@: %@", #type, [json class], json); \
|
RCTLogError(@"Expected NSNumber or NSString for %s, received %@: %@", \
|
||||||
|
#type, [json classForCoder], json); \
|
||||||
} \
|
} \
|
||||||
id value = mapping[json]; \
|
id value = mapping[json]; \
|
||||||
if(!value && [json description].length > 0) { \
|
if(!value && [json description].length > 0) { \
|
||||||
|
|
|
@ -45,7 +45,7 @@ RCT_CONVERTER(NSString *, NSString, description)
|
||||||
}
|
}
|
||||||
return number;
|
return number;
|
||||||
} else if (json && json != [NSNull null]) {
|
} else if (json && json != [NSNull null]) {
|
||||||
RCTLogError(@"JSON value '%@' of class %@ could not be interpreted as a number", json, [json class]);
|
RCTLogError(@"JSON value '%@' of class %@ could not be interpreted as a number", json, [json classForCoder]);
|
||||||
}
|
}
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ RCT_CONVERTER(NSString *, NSString, description)
|
||||||
+ (NSURL *)NSURL:(id)json
|
+ (NSURL *)NSURL:(id)json
|
||||||
{
|
{
|
||||||
if (![json isKindOfClass:[NSString class]]) {
|
if (![json isKindOfClass:[NSString class]]) {
|
||||||
RCTLogError(@"Expected NSString for NSURL, received %@: %@", [json class], json);
|
RCTLogError(@"Expected NSString for NSURL, received %@: %@", [json classForCoder], json);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ RCT_CONVERTER(NSString *, NSString, description)
|
||||||
}
|
}
|
||||||
return date;
|
return date;
|
||||||
} else if (json && json != [NSNull null]) {
|
} else if (json && json != [NSNull null]) {
|
||||||
RCTLogError(@"JSON value '%@' of class %@ could not be interpreted as a date", json, [json class]);
|
RCTLogError(@"JSON value '%@' of class %@ could not be interpreted as a date", json, [json classForCoder]);
|
||||||
}
|
}
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
@ -234,7 +234,8 @@ RCT_ENUM_CONVERTER(UIBarStyle, (@{
|
||||||
((CGFloat *)&result)[i] = [self CGFloat:json[fields[i]]]; \
|
((CGFloat *)&result)[i] = [self CGFloat:json[fields[i]]]; \
|
||||||
} \
|
} \
|
||||||
} else if (json && json != [NSNull null]) { \
|
} else if (json && json != [NSNull null]) { \
|
||||||
RCTLogError(@"Expected NSArray or NSDictionary for %s, received %@: %@", #type, [json class], json); \
|
RCTLogError(@"Expected NSArray or NSDictionary for %s, received %@: %@", \
|
||||||
|
#type, [json classForCoder], json); \
|
||||||
} \
|
} \
|
||||||
return result; \
|
return result; \
|
||||||
} \
|
} \
|
||||||
|
@ -511,8 +512,8 @@ RCT_CGSTRUCT_CONVERTER(CGAffineTransform, (@[
|
||||||
|
|
||||||
} else if (json && ![json isKindOfClass:[NSNull class]]) {
|
} else if (json && ![json isKindOfClass:[NSNull class]]) {
|
||||||
|
|
||||||
RCTLogError(@"Expected NSArray, NSDictionary or NSString for UIColor, \
|
RCTLogError(@"Expected NSArray, NSDictionary or NSString for UIColor, received %@: %@",
|
||||||
received %@: %@", [json class], json);
|
[json classForCoder], json);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default color
|
// Default color
|
||||||
|
@ -538,7 +539,7 @@ RCT_CGSTRUCT_CONVERTER(CGAffineTransform, (@[
|
||||||
// image itself) so as to reduce overhead on subsequent checks of the same input
|
// image itself) so as to reduce overhead on subsequent checks of the same input
|
||||||
|
|
||||||
if (![json isKindOfClass:[NSString class]]) {
|
if (![json isKindOfClass:[NSString class]]) {
|
||||||
RCTLogError(@"Expected NSString for UIImage, received %@: %@", [json class], json);
|
RCTLogError(@"Expected NSString for UIImage, received %@: %@", [json classForCoder], json);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,58 +7,138 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
#import "RCTAssert.h"
|
#import "RCTAssert.h"
|
||||||
#import "RCTRedBox.h"
|
|
||||||
|
|
||||||
#define RCTLOG_INFO 1
|
|
||||||
#define RCTLOG_WARN 2
|
|
||||||
#define RCTLOG_ERROR 3
|
|
||||||
#define RCTLOG_MUSTFIX 4
|
|
||||||
|
|
||||||
// If set to e.g. `RCTLOG_ERROR`, will assert after logging the first error.
|
|
||||||
#if DEBUG
|
|
||||||
#define RCTLOG_FATAL_LEVEL RCTLOG_MUSTFIX
|
|
||||||
#define RCTLOG_REDBOX_LEVEL RCTLOG_ERROR
|
|
||||||
#else
|
|
||||||
#define RCTLOG_FATAL_LEVEL (RCTLOG_MUSTFIX + 1)
|
|
||||||
#define RCTLOG_REDBOX_LEVEL (RCTLOG_MUSTFIX + 1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// If defined, only log messages that match this regex will fatal
|
|
||||||
#define RCTLOG_FATAL_REGEX nil
|
|
||||||
|
|
||||||
extern __unsafe_unretained NSString *RCTLogLevels[];
|
|
||||||
|
|
||||||
#define _RCTLog(_level, ...) do { \
|
|
||||||
NSString *__RCTLog__levelStr = RCTLogLevels[_level - 1]; \
|
|
||||||
NSString *__RCTLog__msg = RCTLogObjects(RCTLogFormat(__FILE__, __LINE__, __PRETTY_FUNCTION__, __VA_ARGS__), __RCTLog__levelStr); \
|
|
||||||
if (_level >= RCTLOG_FATAL_LEVEL) { \
|
|
||||||
BOOL __RCTLog__fail = YES; \
|
|
||||||
if (RCTLOG_FATAL_REGEX) { \
|
|
||||||
NSRegularExpression *__RCTLog__regex = [NSRegularExpression regularExpressionWithPattern:RCTLOG_FATAL_REGEX options:0 error:NULL]; \
|
|
||||||
__RCTLog__fail = [__RCTLog__regex numberOfMatchesInString:__RCTLog__msg options:0 range:NSMakeRange(0, [__RCTLog__msg length])] > 0; \
|
|
||||||
} \
|
|
||||||
RCTCAssert(!__RCTLog__fail, @"RCTLOG_FATAL_LEVEL %@: %@", __RCTLog__levelStr, __RCTLog__msg); \
|
|
||||||
} \
|
|
||||||
if (_level >= RCTLOG_REDBOX_LEVEL) { \
|
|
||||||
[[RCTRedBox sharedInstance] showErrorMessage:__RCTLog__msg]; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define RCTLog(...) _RCTLog(RCTLOG_INFO, __VA_ARGS__)
|
|
||||||
#define RCTLogInfo(...) _RCTLog(RCTLOG_INFO, __VA_ARGS__)
|
|
||||||
#define RCTLogWarn(...) _RCTLog(RCTLOG_WARN, __VA_ARGS__)
|
|
||||||
#define RCTLogError(...) _RCTLog(RCTLOG_ERROR, __VA_ARGS__)
|
|
||||||
#define RCTLogMustFix(...) _RCTLog(RCTLOG_MUSTFIX, __VA_ARGS__)
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
NSString *RCTLogObjects(NSArray *objects, NSString *level);
|
/**
|
||||||
NSArray *RCTLogFormat(const char *file, int lineNumber, const char *funcName, NSString *format, ...) NS_FORMAT_FUNCTION(4,5);
|
* Thresholds for logs to raise an assertion, or display redbox, respectively.
|
||||||
|
* You can override these values when debugging in order to tweak the default
|
||||||
|
* logging behavior.
|
||||||
|
*/
|
||||||
|
#define RCTLOG_FATAL_LEVEL RCTLogLevelMustFix
|
||||||
|
#define RCTLOG_REDBOX_LEVEL RCTLogLevelError
|
||||||
|
|
||||||
void RCTInjectLogFunction(void (^logFunction)(NSString *msg));
|
/**
|
||||||
|
* A regular expression that can be used to selectively limit the throwing of
|
||||||
|
* a exception to specific log contents.
|
||||||
|
*/
|
||||||
|
#define RCTLOG_FATAL_REGEX nil
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An enum representing the severity of the log message.
|
||||||
|
*/
|
||||||
|
typedef NS_ENUM(NSInteger, RCTLogLevel) {
|
||||||
|
RCTLogLevelInfo = 1,
|
||||||
|
RCTLogLevelWarning = 2,
|
||||||
|
RCTLogLevelError = 3,
|
||||||
|
RCTLogLevelMustFix = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A block signature to be used for custom logging functions. In most cases you
|
||||||
|
* will want to pass these arguments to the RCTFormatLog function in order to
|
||||||
|
* generate a string, or use the RCTSimpleLogFunction() constructor to register
|
||||||
|
* a simple function that does not use all of the arguments.
|
||||||
|
*/
|
||||||
|
typedef void (^RCTLogFunction)(
|
||||||
|
RCTLogLevel level,
|
||||||
|
NSString *fileName,
|
||||||
|
NSNumber *lineNumber,
|
||||||
|
NSString *message
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A method to generate a string from a collection of log data. To omit any
|
||||||
|
* particular data from the log, just pass nil or zero for the argument.
|
||||||
|
*/
|
||||||
|
NSString *RCTFormatLog(
|
||||||
|
NSDate *timestamp,
|
||||||
|
NSThread *thread,
|
||||||
|
RCTLogLevel level,
|
||||||
|
NSString *fileName,
|
||||||
|
NSNumber *lineNumber,
|
||||||
|
NSString *message
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A method to generate a log function from a block with a much simpler
|
||||||
|
* template. The message passed to the simpler block is equivalent to the
|
||||||
|
* output of the RCTFormatLog() function.
|
||||||
|
*/
|
||||||
|
RCTLogFunction RCTSimpleLogFunction(void (^logFunction)(RCTLogLevel level, NSString *message));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default logging function used by RCTLogXX.
|
||||||
|
*/
|
||||||
|
extern RCTLogFunction RCTDefaultLogFunction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These methods get and set the current logging threshold. This is the level
|
||||||
|
* below which logs will be ignored. Default is RCTLogLevelInfo for debug and
|
||||||
|
* RCTLogLevelError for production.
|
||||||
|
*/
|
||||||
|
void RCTSetLogThreshold(RCTLogLevel threshold);
|
||||||
|
RCTLogLevel RCTGetLogThreshold(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These methods get and set the current logging function called by the RCTLogXX
|
||||||
|
* macros. You can use these to replace the standard behavior with custom log
|
||||||
|
* functionality.
|
||||||
|
*/
|
||||||
|
void RCTSetLogFunction(RCTLogFunction logFunction);
|
||||||
|
RCTLogFunction RCTGetLogFunction(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This appends additional code to the existing log function, without replacing
|
||||||
|
* the existing functionality. Useful if you just want to forward logs to an
|
||||||
|
* extra service without changing the default behavior.
|
||||||
|
*/
|
||||||
|
void RCTAddLogFunction(RCTLogFunction logFunction);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method adds a conditional prefix to any messages logged within the scope
|
||||||
|
* of the passed block. This is useful for adding additional context to log
|
||||||
|
* messages. The block will be performed synchronously on the current thread.
|
||||||
|
*/
|
||||||
|
void RCTPerformBlockWithLogPrefix(void (^block)(void), NSString *prefix);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private logging functions - ignore these.
|
||||||
|
*/
|
||||||
|
void _RCTLogFormat(RCTLogLevel, const char *, int, NSString *, ...) NS_FORMAT_FUNCTION(4,5);
|
||||||
|
#define _RCTLog(lvl, ...) do { \
|
||||||
|
NSString *msg = [NSString stringWithFormat:__VA_ARGS__]; \
|
||||||
|
if (lvl >= RCTLOG_FATAL_LEVEL) { \
|
||||||
|
BOOL fail = YES; \
|
||||||
|
if (RCTLOG_FATAL_REGEX) { \
|
||||||
|
if ([msg rangeOfString:RCTLOG_FATAL_REGEX options:NSRegularExpressionSearch].length) { \
|
||||||
|
fail = NO; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
RCTCAssert(!fail, @"FATAL ERROR: %@", msg); \
|
||||||
|
}\
|
||||||
|
_RCTLogFormat(lvl, __FILE__, __LINE__, __VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Legacy injection function - don't use this.
|
||||||
|
*/
|
||||||
|
void RCTInjectLogFunction(void (^)(NSString *msg));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logging macros. Use these to log information, warnings and errors in your
|
||||||
|
* own code.
|
||||||
|
*/
|
||||||
|
#define RCTLog(...) _RCTLog(RCTLogLevelInfo, __VA_ARGS__)
|
||||||
|
#define RCTLogInfo(...) _RCTLog(RCTLogLevelInfo, __VA_ARGS__)
|
||||||
|
#define RCTLogWarn(...) _RCTLog(RCTLogLevelWarning, __VA_ARGS__)
|
||||||
|
#define RCTLogError(...) _RCTLog(RCTLogLevelError, __VA_ARGS__)
|
||||||
|
#define RCTLogMustFix(...) _RCTLog(RCTLogLevelMustFix, __VA_ARGS__)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,85 +9,218 @@
|
||||||
|
|
||||||
#import "RCTLog.h"
|
#import "RCTLog.h"
|
||||||
|
|
||||||
|
#import "RCTAssert.h"
|
||||||
#import "RCTBridge.h"
|
#import "RCTBridge.h"
|
||||||
|
#import "RCTRedBox.h"
|
||||||
|
|
||||||
__unsafe_unretained NSString *RCTLogLevels[] = {
|
@interface RCTBridge (Logging)
|
||||||
@"info",
|
|
||||||
@"warn",
|
+ (void)logMessage:(NSString *)message level:(NSString *)level;
|
||||||
@"error",
|
|
||||||
@"mustfix"
|
@end
|
||||||
|
|
||||||
|
static NSString *const RCTLogPrefixStack = @"RCTLogPrefixStack";
|
||||||
|
|
||||||
|
const char *RCTLogLevels[] = {
|
||||||
|
"info",
|
||||||
|
"warn",
|
||||||
|
"error",
|
||||||
|
"mustfix"
|
||||||
};
|
};
|
||||||
|
|
||||||
static void (^RCTInjectedLogFunction)(NSString *msg);
|
static RCTLogFunction RCTCurrentLogFunction;
|
||||||
|
static RCTLogLevel RCTCurrentLogThreshold;
|
||||||
|
|
||||||
void RCTInjectLogFunction(void (^logFunction)(NSString *msg)) {
|
void RCTLogSetup(void) __attribute__((constructor));
|
||||||
RCTInjectedLogFunction = logFunction;
|
void RCTLogSetup()
|
||||||
}
|
|
||||||
|
|
||||||
static inline NSString *_RCTLogPreamble(const char *file, int lineNumber, const char *funcName)
|
|
||||||
{
|
{
|
||||||
NSString *threadName = [[NSThread currentThread] name];
|
RCTCurrentLogFunction = RCTDefaultLogFunction;
|
||||||
NSString *fileName=[[NSString stringWithUTF8String:file] lastPathComponent];
|
|
||||||
if (!threadName || threadName.length <= 0) {
|
|
||||||
threadName = [NSString stringWithFormat:@"%p", [NSThread currentThread]];
|
|
||||||
}
|
|
||||||
return [NSString stringWithFormat:@"[RCTLog][tid:%@][%@:%d]>", threadName, fileName, lineNumber];
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO (#5906496): Does this need to be tied to RCTBridge?
|
#if DEBUG
|
||||||
NSString *RCTLogObjects(NSArray *objects, NSString *level)
|
RCTCurrentLogThreshold = RCTLogLevelInfo - 1;
|
||||||
{
|
#else
|
||||||
NSString *str = objects[0];
|
RCTCurrentLogThreshold = RCTLogLevelError;
|
||||||
#if TARGET_IPHONE_SIMULATOR
|
|
||||||
if ([RCTBridge hasValidJSExecutor]) {
|
|
||||||
fprintf(stderr, "%s\n", [str UTF8String]); // don't print timestamps and other junk
|
|
||||||
[RCTBridge log:objects level:level];
|
|
||||||
} else
|
|
||||||
#endif
|
#endif
|
||||||
{
|
|
||||||
// Print normal errors with timestamps when not in simulator.
|
|
||||||
// Non errors are already compiled out above, so log as error here.
|
|
||||||
if (RCTInjectedLogFunction) {
|
|
||||||
RCTInjectedLogFunction(str);
|
|
||||||
} else {
|
|
||||||
NSLog(@">\n %@", str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns array of objects. First arg is a simple string to print, remaining args
|
RCTLogFunction RCTDefaultLogFunction = ^(
|
||||||
// are objects to pass through to the debugger so they are inspectable in the console.
|
RCTLogLevel level,
|
||||||
NSArray *RCTLogFormat(const char *file, int lineNumber, const char *funcName, NSString *format, ...)
|
NSString *fileName,
|
||||||
|
NSNumber *lineNumber,
|
||||||
|
NSString *message
|
||||||
|
)
|
||||||
{
|
{
|
||||||
|
NSString *log = RCTFormatLog(
|
||||||
|
[NSDate date], [NSThread currentThread], level, fileName, lineNumber, message
|
||||||
|
);
|
||||||
|
fprintf(stderr, "%s\n", log.UTF8String);
|
||||||
|
};
|
||||||
|
|
||||||
|
void RCTSetLogFunction(RCTLogFunction logFunction)
|
||||||
|
{
|
||||||
|
RCTCurrentLogFunction = logFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
RCTLogFunction RCTGetLogFunction()
|
||||||
|
{
|
||||||
|
return RCTCurrentLogFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RCTAddLogFunction(RCTLogFunction logFunction)
|
||||||
|
{
|
||||||
|
RCTLogFunction existing = RCTCurrentLogFunction;
|
||||||
|
if (existing) {
|
||||||
|
RCTCurrentLogFunction = ^(RCTLogLevel level,
|
||||||
|
NSString *fileName,
|
||||||
|
NSNumber *lineNumber,
|
||||||
|
NSString *message) {
|
||||||
|
|
||||||
|
existing(level, fileName, lineNumber, message);
|
||||||
|
logFunction(level, fileName, lineNumber, message);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
RCTCurrentLogFunction = logFunction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RCTPerformBlockWithLogPrefix(void (^block)(void), NSString *prefix)
|
||||||
|
{
|
||||||
|
NSMutableDictionary *threadDictionary = [NSThread currentThread].threadDictionary;
|
||||||
|
NSMutableArray *prefixStack = threadDictionary[RCTLogPrefixStack];
|
||||||
|
if (!prefixStack) {
|
||||||
|
prefixStack = [[NSMutableArray alloc] init];
|
||||||
|
threadDictionary[RCTLogPrefixStack] = prefixStack;
|
||||||
|
}
|
||||||
|
[prefixStack addObject:prefix];
|
||||||
|
block();
|
||||||
|
[prefixStack removeLastObject];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *RCTFormatLog(
|
||||||
|
NSDate *timestamp,
|
||||||
|
NSThread *thread,
|
||||||
|
RCTLogLevel level,
|
||||||
|
NSString *fileName,
|
||||||
|
NSNumber *lineNumber,
|
||||||
|
NSString *message
|
||||||
|
)
|
||||||
|
{
|
||||||
|
NSMutableString *log = [[NSMutableString alloc] init];
|
||||||
|
if (timestamp) {
|
||||||
|
static NSDateFormatter *formatter;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
formatter = [[NSDateFormatter alloc] init];
|
||||||
|
formatter.dateFormat = formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss.SSS ";
|
||||||
|
});
|
||||||
|
[log appendString:[formatter stringFromDate:timestamp]];
|
||||||
|
}
|
||||||
|
[log appendString:@"[react]"];
|
||||||
|
if (level) {
|
||||||
|
[log appendFormat:@"[%s]", RCTLogLevels[level - 1]];
|
||||||
|
}
|
||||||
|
if (thread) {
|
||||||
|
NSString *threadName = thread.name;
|
||||||
|
if (threadName.length == 0) {
|
||||||
|
#if DEBUG
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||||
|
threadName = @(dispatch_queue_get_label(dispatch_get_current_queue()));
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#else
|
||||||
|
threadName = [NSString stringWithFormat:@"%p", thread];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
[log appendFormat:@"[tid:%@]", threadName];
|
||||||
|
}
|
||||||
|
if (fileName) {
|
||||||
|
fileName = [fileName lastPathComponent];
|
||||||
|
if (lineNumber) {
|
||||||
|
[log appendFormat:@"[%@:%@]", fileName, lineNumber];
|
||||||
|
} else {
|
||||||
|
[log appendFormat:@"[%@]", fileName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (message) {
|
||||||
|
[log appendString:@" "];
|
||||||
|
[log appendString:message];
|
||||||
|
}
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
RCTLogFunction RCTSimpleLogFunction(void (^logFunction)(RCTLogLevel level, NSString *message))
|
||||||
|
{
|
||||||
|
return ^(RCTLogLevel level,
|
||||||
|
NSString *fileName,
|
||||||
|
NSNumber *lineNumber,
|
||||||
|
NSString *message) {
|
||||||
|
|
||||||
|
logFunction(level, RCTFormatLog(
|
||||||
|
[NSDate date], [NSThread currentThread], level, fileName, lineNumber, message
|
||||||
|
));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void _RCTLogFormat(RCTLogLevel level, const char *fileName, int lineNumber, NSString *format, ...)
|
||||||
|
{
|
||||||
|
if (RCTCurrentLogFunction && level >= RCTCurrentLogThreshold) {
|
||||||
|
|
||||||
|
// Get message
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
NSString *preamble = _RCTLogPreamble(file, lineNumber, funcName);
|
__block NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
// Add prefix
|
||||||
|
NSMutableDictionary *threadDictionary = [NSThread currentThread].threadDictionary;
|
||||||
|
NSArray *prefixStack = threadDictionary[RCTLogPrefixStack];
|
||||||
|
NSString *prefix = [prefixStack lastObject];
|
||||||
|
if (prefix) {
|
||||||
|
message = [prefix stringByAppendingString:message];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call log function
|
||||||
|
RCTCurrentLogFunction(
|
||||||
|
level, fileName ? @(fileName) : nil, (lineNumber >= 0) ? @(lineNumber) : nil, message
|
||||||
|
);
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
|
||||||
|
// Log to red box
|
||||||
|
if (level >= RCTLOG_REDBOX_LEVEL) {
|
||||||
|
[[RCTRedBox sharedInstance] showErrorMessage:message];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log to JS executor
|
||||||
|
if ([RCTBridge hasValidJSExecutor]) {
|
||||||
|
[RCTBridge logMessage:message level:level ? @(RCTLogLevels[level - 1]) : @"info"];
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
// Pull out NSObjects so we can pass them through as inspectable objects to the js debugger
|
|
||||||
NSArray *formatParts = [format componentsSeparatedByString:@"%"];
|
|
||||||
NSMutableArray *objects = [NSMutableArray arrayWithObject:preamble];
|
|
||||||
BOOL valid = YES;
|
|
||||||
for (int i = 0; i < formatParts.count; i++) {
|
|
||||||
if (i == 0) { // first part is always a string
|
|
||||||
[objects addObject:formatParts[i]];
|
|
||||||
} else {
|
|
||||||
if (valid && [formatParts[i] length] && [formatParts[i] characterAtIndex:0] == '@') {
|
|
||||||
id obj = va_arg(args, id);
|
|
||||||
[objects addObject:obj ?: @"null"];
|
|
||||||
[objects addObject:[formatParts[i] substringFromIndex:1]]; // remove formatting char
|
|
||||||
} else {
|
|
||||||
// We could determine the type (double, int?) of the va_arg by parsing the formatPart, but for now we just bail.
|
|
||||||
valid = NO;
|
|
||||||
[objects addObject:[NSString stringWithFormat:@"unknown object for %%%@", formatParts[i]]];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - Deprecated
|
||||||
|
|
||||||
|
void RCTInjectLogFunction(void (^logFunction)(NSString *msg))
|
||||||
|
{
|
||||||
|
RCTSetLogFunction(^(RCTLogLevel level,
|
||||||
|
NSString *fileName,
|
||||||
|
NSNumber *lineNumber,
|
||||||
|
NSString *message) {
|
||||||
|
|
||||||
|
if (level > RCTLogLevelError) {
|
||||||
|
|
||||||
|
// Use custom log function
|
||||||
|
NSString *loc = fileName ? [NSString stringWithFormat:@"[%@:%@] ", fileName, lineNumber] : @"";
|
||||||
|
logFunction([loc stringByAppendingString:message]);
|
||||||
|
|
||||||
|
} else if (RCTDefaultLogFunction && level >= RCTCurrentLogThreshold) {
|
||||||
|
|
||||||
|
// Use default logger
|
||||||
|
RCTDefaultLogFunction(level, fileName, lineNumber, message);
|
||||||
}
|
}
|
||||||
va_end(args);
|
});
|
||||||
va_start(args, format);
|
|
||||||
NSString *strOut = [preamble stringByAppendingString:[[NSString alloc] initWithFormat:format arguments:args]];
|
|
||||||
va_end(args);
|
|
||||||
NSMutableArray *objectsOut = [NSMutableArray arrayWithObject:strOut];
|
|
||||||
[objectsOut addObjectsFromArray:objects];
|
|
||||||
return objectsOut;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,9 @@ extern NSString *const RCTReloadViewsNotification;
|
||||||
|
|
||||||
@interface RCTRootView : UIView <RCTInvalidating>
|
@interface RCTRootView : UIView <RCTInvalidating>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* - Designated initializer -
|
||||||
|
*/
|
||||||
- (instancetype)initWithBridge:(RCTBridge *)bridge
|
- (instancetype)initWithBridge:(RCTBridge *)bridge
|
||||||
moduleName:(NSString *)moduleName NS_DESIGNATED_INITIALIZER;
|
moduleName:(NSString *)moduleName NS_DESIGNATED_INITIALIZER;
|
||||||
|
|
||||||
|
@ -39,6 +42,10 @@ extern NSString *const RCTReloadViewsNotification;
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, copy, readonly) NSString *moduleName;
|
@property (nonatomic, copy, readonly) NSString *moduleName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bridge used by the root view. Bridges can be shared between multiple
|
||||||
|
* root views, so you can use this property to initialize another RCTRootView.
|
||||||
|
*/
|
||||||
@property (nonatomic, strong, readonly) RCTBridge *bridge;
|
@property (nonatomic, strong, readonly) RCTBridge *bridge;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
#import "RCTEventDispatcher.h"
|
#import "RCTEventDispatcher.h"
|
||||||
#import "RCTKeyCommands.h"
|
#import "RCTKeyCommands.h"
|
||||||
#import "RCTLog.h"
|
#import "RCTLog.h"
|
||||||
#import "RCTRedBox.h"
|
|
||||||
#import "RCTSourceCode.h"
|
#import "RCTSourceCode.h"
|
||||||
#import "RCTTouchHandler.h"
|
#import "RCTTouchHandler.h"
|
||||||
#import "RCTUIManager.h"
|
#import "RCTUIManager.h"
|
||||||
|
|
|
@ -38,23 +38,18 @@ static JSValueRef RCTNativeLoggingHook(JSContextRef context, JSObjectRef object,
|
||||||
if (!string) {
|
if (!string) {
|
||||||
return JSValueMakeUndefined(context);
|
return JSValueMakeUndefined(context);
|
||||||
}
|
}
|
||||||
|
NSString *message = (__bridge_transfer NSString *)JSStringCopyCFString(kCFAllocatorDefault, string);
|
||||||
NSString *str = (__bridge_transfer NSString *)JSStringCopyCFString(kCFAllocatorDefault, string);
|
JSStringRelease(string);
|
||||||
NSError *error = nil;
|
|
||||||
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:
|
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:
|
||||||
@"( stack: )?([_a-z0-9]*)@?(http://|file:///)[a-z.0-9:/_-]+/([a-z0-9_]+).includeRequire.runModule.bundle(:[0-9]+:[0-9]+)"
|
@"( stack: )?([_a-z0-9]*)@?(http://|file:///)[a-z.0-9:/_-]+/([a-z0-9_]+).includeRequire.runModule.bundle(:[0-9]+:[0-9]+)"
|
||||||
options:NSRegularExpressionCaseInsensitive
|
options:NSRegularExpressionCaseInsensitive
|
||||||
error:&error];
|
error:NULL];
|
||||||
NSString *modifiedString = [regex stringByReplacingMatchesInString:str options:0 range:NSMakeRange(0, [str length]) withTemplate:@"[$4$5] \t$2"];
|
message = [regex stringByReplacingMatchesInString:message
|
||||||
|
options:0
|
||||||
|
range:(NSRange){0, message.length}
|
||||||
|
withTemplate:@"[$4$5] \t$2"];
|
||||||
|
|
||||||
modifiedString = [@"RCTJSLog> " stringByAppendingString:modifiedString];
|
_RCTLogFormat(0, NULL, -1, @"%@", message);
|
||||||
#if TARGET_IPHONE_SIMULATOR
|
|
||||||
fprintf(stderr, "%s\n", [modifiedString UTF8String]); // don't print timestamps and other junk
|
|
||||||
#else
|
|
||||||
// Print normal errors with timestamps to files when not in simulator.
|
|
||||||
RCTLogObjects(@[modifiedString], @"log");
|
|
||||||
#endif
|
|
||||||
JSStringRelease(string);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return JSValueMakeUndefined(context);
|
return JSValueMakeUndefined(context);
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#import "RCTAlertManager.h"
|
#import "RCTAlertManager.h"
|
||||||
|
|
||||||
|
#import "RCTAssert.h"
|
||||||
#import "RCTLog.h"
|
#import "RCTLog.h"
|
||||||
|
|
||||||
@interface RCTAlertManager() <UIAlertViewDelegate>
|
@interface RCTAlertManager() <UIAlertViewDelegate>
|
||||||
|
|
|
@ -197,6 +197,11 @@ static UIViewAnimationCurve UIViewAnimationCurveFromRCTAnimationType(RCTAnimatio
|
||||||
|
|
||||||
@synthesize bridge = _bridge;
|
@synthesize bridge = _bridge;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declared in RCTBridge.
|
||||||
|
*/
|
||||||
|
extern NSString *RCTBridgeModuleNameForClass(Class cls);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function derives the view name automatically
|
* This function derives the view name automatically
|
||||||
* from the module name.
|
* from the module name.
|
||||||
|
@ -334,7 +339,7 @@ static NSString *RCTViewNameForModuleName(NSString *moduleName)
|
||||||
|
|
||||||
dispatch_async(_bridge.shadowQueue, ^{
|
dispatch_async(_bridge.shadowQueue, ^{
|
||||||
RCTShadowView *rootShadowView = _shadowViewRegistry[reactTag];
|
RCTShadowView *rootShadowView = _shadowViewRegistry[reactTag];
|
||||||
RCTAssert(rootShadowView != nil, @"Could not locate root view with tag %@", reactTag);
|
RCTAssert(rootShadowView != nil, @"Could not locate root view with tag #%@", reactTag);
|
||||||
rootShadowView.frame = frame;
|
rootShadowView.frame = frame;
|
||||||
[rootShadowView updateLayout];
|
[rootShadowView updateLayout];
|
||||||
|
|
||||||
|
@ -672,7 +677,7 @@ static NSString *RCTViewNameForModuleName(NSString *moduleName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL RCTCallPropertySetter(SEL setter, id value, id view, id defaultView, RCTViewManager *manager)
|
static BOOL RCTCallPropertySetter(NSString *key, SEL setter, id value, id view, id defaultView, RCTViewManager *manager)
|
||||||
{
|
{
|
||||||
// TODO: cache respondsToSelector tests
|
// TODO: cache respondsToSelector tests
|
||||||
if ([manager respondsToSelector:setter]) {
|
if ([manager respondsToSelector:setter]) {
|
||||||
|
@ -681,7 +686,25 @@ static BOOL RCTCallPropertySetter(SEL setter, id value, id view, id defaultView,
|
||||||
value = nil;
|
value = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void (^block)() = ^{
|
||||||
((void (*)(id, SEL, id, id, id))objc_msgSend)(manager, setter, value, view, defaultView);
|
((void (*)(id, SEL, id, id, id))objc_msgSend)(manager, setter, value, view, defaultView);
|
||||||
|
};
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
|
||||||
|
NSString *viewName = RCTViewNameForModuleName(RCTBridgeModuleNameForClass([manager class]));
|
||||||
|
NSString *logPrefix = [NSString stringWithFormat:
|
||||||
|
@"Error setting property '%@' of %@ with tag #%@: ",
|
||||||
|
key, viewName, [view reactTag]];
|
||||||
|
|
||||||
|
RCTPerformBlockWithLogPrefix(block, logPrefix);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
block();
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
return NO;
|
return NO;
|
||||||
|
@ -693,7 +716,7 @@ static void RCTSetViewProps(NSDictionary *props, UIView *view,
|
||||||
[props enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
|
[props enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
|
||||||
|
|
||||||
SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set_%@:forView:withDefaultView:", key]);
|
SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set_%@:forView:withDefaultView:", key]);
|
||||||
RCTCallPropertySetter(setter, obj, view, defaultView, manager);
|
RCTCallPropertySetter(key, setter, obj, view, defaultView, manager);
|
||||||
|
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
@ -704,7 +727,7 @@ static void RCTSetShadowViewProps(NSDictionary *props, RCTShadowView *shadowView
|
||||||
[props enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
|
[props enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
|
||||||
|
|
||||||
SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set_%@:forShadowView:withDefaultView:", key]);
|
SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set_%@:forShadowView:withDefaultView:", key]);
|
||||||
RCTCallPropertySetter(setter, obj, shadowView, defaultView, manager);
|
RCTCallPropertySetter(key, setter, obj, shadowView, defaultView, manager);
|
||||||
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
@ -875,7 +898,7 @@ static void RCTSetShadowViewProps(NSDictionary *props, RCTShadowView *shadowView
|
||||||
[self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
|
[self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
|
||||||
UIView *view = viewRegistry[reactTag];
|
UIView *view = viewRegistry[reactTag];
|
||||||
if (!view) {
|
if (!view) {
|
||||||
RCTLogError(@"measure cannot find view with tag %@", reactTag);
|
RCTLogError(@"measure cannot find view with tag #%@", reactTag);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CGRect frame = view.frame;
|
CGRect frame = view.frame;
|
||||||
|
@ -1039,7 +1062,7 @@ static void RCTMeasureLayout(RCTShadowView *view,
|
||||||
uiManager.mainScrollView = (id<RCTScrollableProtocol>)rkObject;
|
uiManager.mainScrollView = (id<RCTScrollableProtocol>)rkObject;
|
||||||
((id<RCTScrollableProtocol>)rkObject).nativeMainScrollDelegate = uiManager.nativeMainScrollDelegate;
|
((id<RCTScrollableProtocol>)rkObject).nativeMainScrollDelegate = uiManager.nativeMainScrollDelegate;
|
||||||
} else {
|
} else {
|
||||||
RCTCAssert(NO, @"Tag %@ does not conform to RCTScrollableProtocol", reactTag);
|
RCTCAssert(NO, @"Tag #%@ does not conform to RCTScrollableProtocol", reactTag);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uiManager.mainScrollView = nil;
|
uiManager.mainScrollView = nil;
|
||||||
|
@ -1056,7 +1079,7 @@ static void RCTMeasureLayout(RCTShadowView *view,
|
||||||
if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
|
if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
|
||||||
[(id<RCTScrollableProtocol>)view scrollToOffset:CGPointMake([offsetX floatValue], [offsetY floatValue]) animated:YES];
|
[(id<RCTScrollableProtocol>)view scrollToOffset:CGPointMake([offsetX floatValue], [offsetY floatValue]) animated:YES];
|
||||||
} else {
|
} else {
|
||||||
RCTLogError(@"tried to scrollToOffset: on non-RCTScrollableProtocol view %@ with tag %@", view, reactTag);
|
RCTLogError(@"tried to scrollToOffset: on non-RCTScrollableProtocol view %@ with tag #%@", view, reactTag);
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
@ -1070,7 +1093,7 @@ static void RCTMeasureLayout(RCTShadowView *view,
|
||||||
if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
|
if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
|
||||||
[(id<RCTScrollableProtocol>)view scrollToOffset:CGPointMake([offsetX floatValue], [offsetY floatValue]) animated:NO];
|
[(id<RCTScrollableProtocol>)view scrollToOffset:CGPointMake([offsetX floatValue], [offsetY floatValue]) animated:NO];
|
||||||
} else {
|
} else {
|
||||||
RCTLogError(@"tried to scrollToOffset: on non-RCTScrollableProtocol view %@ with tag %@", view, reactTag);
|
RCTLogError(@"tried to scrollToOffset: on non-RCTScrollableProtocol view %@ with tag #%@", view, reactTag);
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
@ -1084,7 +1107,7 @@ static void RCTMeasureLayout(RCTShadowView *view,
|
||||||
if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
|
if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
|
||||||
[(id<RCTScrollableProtocol>)view zoomToRect:[RCTConvert CGRect:rectDict] animated:YES];
|
[(id<RCTScrollableProtocol>)view zoomToRect:[RCTConvert CGRect:rectDict] animated:YES];
|
||||||
} else {
|
} else {
|
||||||
RCTLogError(@"tried to zoomToRect: on non-RCTScrollableProtocol view %@ with tag %@", view, reactTag);
|
RCTLogError(@"tried to zoomToRect: on non-RCTScrollableProtocol view %@ with tag #%@", view, reactTag);
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ RCT_DEPRECATED_VIEW_PROPERTY(throttleScrollCallbackMS, scrollEventThrottle)
|
||||||
|
|
||||||
UIView *view = viewRegistry[reactTag];
|
UIView *view = viewRegistry[reactTag];
|
||||||
if (!view) {
|
if (!view) {
|
||||||
RCTLogError(@"Cannot find view with tag %@", reactTag);
|
RCTLogError(@"Cannot find view with tag #%@", reactTag);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue