mirror of
https://github.com/status-im/react-native.git
synced 2025-01-21 06:49:39 +00:00
b672294858
Summary: public The +[RCTConvert UIImage:] function, while convenient, is inherently limited by being synchronous, which means that it cannot be used to load remote images, and may not be efficient for local images either. It's also unable to access the bridge, which means that it cannot take advantage of the modular image-loading pipeline. This diff introduces a new RCTImageSource class which can be used to pass image source objects over the bridge and defer loading until later. I've also added automatic application of the `resolveAssetSource()` function based on prop type, and fixed up the image logic in NavigatorIOS and TabBarIOS. Reviewed By: javache Differential Revision: D2631541 fb-gh-sync-id: 6604635e8bb5394425102487f1ee7cd729321877
253 lines
7.4 KiB
Objective-C
253 lines
7.4 KiB
Objective-C
/**
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*/
|
|
|
|
#import "RCTLog.h"
|
|
|
|
#include <asl.h>
|
|
|
|
#import "RCTAssert.h"
|
|
#import "RCTBridge.h"
|
|
#import "RCTDefines.h"
|
|
#import "RCTRedBox.h"
|
|
|
|
@interface RCTBridge ()
|
|
|
|
+ (RCTBridge *)currentBridge;
|
|
- (void)logMessage:(NSString *)message level:(NSString *)level;
|
|
|
|
@end
|
|
|
|
static NSString *const RCTLogFunctionStack = @"RCTLogFunctionStack";
|
|
|
|
const char *RCTLogLevels[] = {
|
|
"trace",
|
|
"info",
|
|
"warn",
|
|
"error",
|
|
"fatal",
|
|
};
|
|
|
|
#if RCT_DEBUG
|
|
static const RCTLogLevel RCTDefaultLogThreshold = RCTLogLevelInfo - 1;
|
|
#else
|
|
static const RCTLogLevel RCTDefaultLogThreshold = RCTLogLevelError;
|
|
#endif
|
|
|
|
static RCTLogFunction RCTCurrentLogFunction;
|
|
static RCTLogLevel RCTCurrentLogThreshold = RCTDefaultLogThreshold;
|
|
|
|
RCTLogLevel RCTGetLogThreshold()
|
|
{
|
|
return RCTCurrentLogThreshold;
|
|
}
|
|
|
|
void RCTSetLogThreshold(RCTLogLevel threshold) {
|
|
RCTCurrentLogThreshold = threshold;
|
|
}
|
|
|
|
RCTLogFunction RCTDefaultLogFunction = ^(
|
|
RCTLogLevel level,
|
|
__unused RCTLogSource source,
|
|
NSString *fileName,
|
|
NSNumber *lineNumber,
|
|
NSString *message
|
|
)
|
|
{
|
|
NSString *log = RCTFormatLog([NSDate date], level, fileName, lineNumber, message);
|
|
fprintf(stderr, "%s\n", log.UTF8String);
|
|
fflush(stderr);
|
|
|
|
int aslLevel;
|
|
switch(level) {
|
|
case RCTLogLevelTrace:
|
|
aslLevel = ASL_LEVEL_DEBUG;
|
|
break;
|
|
case RCTLogLevelInfo:
|
|
aslLevel = ASL_LEVEL_NOTICE;
|
|
break;
|
|
case RCTLogLevelWarning:
|
|
aslLevel = ASL_LEVEL_WARNING;
|
|
break;
|
|
case RCTLogLevelError:
|
|
aslLevel = ASL_LEVEL_ERR;
|
|
break;
|
|
case RCTLogLevelFatal:
|
|
aslLevel = ASL_LEVEL_CRIT;
|
|
break;
|
|
}
|
|
asl_log(NULL, NULL, aslLevel, "%s", message.UTF8String);
|
|
};
|
|
|
|
void RCTSetLogFunction(RCTLogFunction logFunction)
|
|
{
|
|
RCTCurrentLogFunction = logFunction;
|
|
}
|
|
|
|
RCTLogFunction RCTGetLogFunction()
|
|
{
|
|
if (!RCTCurrentLogFunction) {
|
|
RCTCurrentLogFunction = RCTDefaultLogFunction;
|
|
}
|
|
return RCTCurrentLogFunction;
|
|
}
|
|
|
|
void RCTAddLogFunction(RCTLogFunction logFunction)
|
|
{
|
|
RCTLogFunction existing = RCTGetLogFunction();
|
|
if (existing) {
|
|
RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
|
|
existing(level, source, fileName, lineNumber, message);
|
|
logFunction(level, source, fileName, lineNumber, message);
|
|
});
|
|
} else {
|
|
RCTSetLogFunction(logFunction);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* returns the topmost stacked log function for the current thread, which
|
|
* may not be the same as the current value of RCTCurrentLogFunction.
|
|
*/
|
|
static RCTLogFunction RCTGetLocalLogFunction()
|
|
{
|
|
NSMutableDictionary *threadDictionary = [NSThread currentThread].threadDictionary;
|
|
NSArray<RCTLogFunction> *functionStack = threadDictionary[RCTLogFunctionStack];
|
|
RCTLogFunction logFunction = functionStack.lastObject;
|
|
if (logFunction) {
|
|
return logFunction;
|
|
}
|
|
return RCTGetLogFunction();
|
|
}
|
|
|
|
void RCTPerformBlockWithLogFunction(void (^block)(void), RCTLogFunction logFunction)
|
|
{
|
|
NSMutableDictionary *threadDictionary = [NSThread currentThread].threadDictionary;
|
|
NSMutableArray<RCTLogFunction> *functionStack = threadDictionary[RCTLogFunctionStack];
|
|
if (!functionStack) {
|
|
functionStack = [NSMutableArray new];
|
|
threadDictionary[RCTLogFunctionStack] = functionStack;
|
|
}
|
|
[functionStack addObject:logFunction];
|
|
block();
|
|
[functionStack removeLastObject];
|
|
}
|
|
|
|
void RCTPerformBlockWithLogPrefix(void (^block)(void), NSString *prefix)
|
|
{
|
|
RCTLogFunction logFunction = RCTGetLocalLogFunction();
|
|
if (logFunction) {
|
|
RCTPerformBlockWithLogFunction(block, ^(RCTLogLevel level, RCTLogSource source,
|
|
NSString *fileName, NSNumber *lineNumber,
|
|
NSString *message) {
|
|
logFunction(level, source, fileName, lineNumber, [prefix stringByAppendingString:message]);
|
|
});
|
|
}
|
|
}
|
|
|
|
NSString *RCTFormatLog(
|
|
NSDate *timestamp,
|
|
RCTLogLevel level,
|
|
NSString *fileName,
|
|
NSNumber *lineNumber,
|
|
NSString *message
|
|
)
|
|
{
|
|
NSMutableString *log = [NSMutableString new];
|
|
if (timestamp) {
|
|
static NSDateFormatter *formatter;
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
formatter = [NSDateFormatter new];
|
|
formatter.dateFormat = formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss.SSS ";
|
|
});
|
|
[log appendString:[formatter stringFromDate:timestamp]];
|
|
}
|
|
if (level) {
|
|
[log appendFormat:@"[%s]", RCTLogLevels[level - 1]];
|
|
}
|
|
|
|
[log appendFormat:@"[tid:%@]", RCTCurrentThreadName()];
|
|
|
|
if (fileName) {
|
|
fileName = fileName.lastPathComponent;
|
|
if (lineNumber) {
|
|
[log appendFormat:@"[%@:%@]", fileName, lineNumber];
|
|
} else {
|
|
[log appendFormat:@"[%@]", fileName];
|
|
}
|
|
}
|
|
if (message) {
|
|
[log appendString:@" "];
|
|
[log appendString:message];
|
|
}
|
|
return log;
|
|
}
|
|
|
|
void _RCTLogNativeInternal(RCTLogLevel level, const char *fileName, int lineNumber, NSString *format, ...)
|
|
{
|
|
RCTLogFunction logFunction = RCTGetLocalLogFunction();
|
|
BOOL log = RCT_DEBUG || (logFunction != nil);
|
|
if (log && level >= RCTGetLogThreshold()) {
|
|
// Get message
|
|
va_list args;
|
|
va_start(args, format);
|
|
NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
|
|
va_end(args);
|
|
|
|
// Call log function
|
|
if (logFunction) {
|
|
logFunction(level, RCTLogSourceNative, fileName ? @(fileName) : nil, lineNumber > 0 ? @(lineNumber) : nil, message);
|
|
}
|
|
|
|
#if RCT_DEBUG
|
|
|
|
// Log to red box in debug mode.
|
|
if ([UIApplication sharedApplication] && level >= RCTLOG_REDBOX_LEVEL) {
|
|
NSArray<NSString *> *stackSymbols = [NSThread callStackSymbols];
|
|
NSMutableArray<NSDictionary *> *stack =
|
|
[NSMutableArray arrayWithCapacity:(stackSymbols.count - 1)];
|
|
[stackSymbols enumerateObjectsUsingBlock:^(NSString *frameSymbols, NSUInteger idx, __unused BOOL *stop) {
|
|
if (idx > 0) { // don't include the current frame
|
|
NSString *address = [[frameSymbols componentsSeparatedByString:@"0x"][1] componentsSeparatedByString:@" "][0];
|
|
NSRange addressRange = [frameSymbols rangeOfString:address];
|
|
NSString *methodName = [frameSymbols substringFromIndex:(addressRange.location + addressRange.length + 1)];
|
|
if (idx == 1 && fileName) {
|
|
NSString *file = [@(fileName) componentsSeparatedByString:@"/"].lastObject;
|
|
[stack addObject:@{@"methodName": methodName, @"file": file, @"lineNumber": @(lineNumber)}];
|
|
} else {
|
|
[stack addObject:@{@"methodName": methodName}];
|
|
}
|
|
}
|
|
}];
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
// red box is thread safe, but by deferring to main queue we avoid a startup
|
|
// race condition that causes the module to be accessed before it has loaded
|
|
[[RCTBridge currentBridge].redBox showErrorMessage:message withStack:stack];
|
|
});
|
|
}
|
|
|
|
// Log to JS executor
|
|
[[RCTBridge currentBridge] logMessage:message level:level ? @(RCTLogLevels[level]) : @"info"];
|
|
|
|
#endif
|
|
|
|
}
|
|
}
|
|
|
|
void _RCTLogJavaScriptInternal(RCTLogLevel level, NSString *message)
|
|
{
|
|
RCTLogFunction logFunction = RCTGetLocalLogFunction();
|
|
BOOL log = RCT_DEBUG || (logFunction != nil);
|
|
if (log && level >= RCTGetLogThreshold()) {
|
|
if (logFunction) {
|
|
logFunction(level, RCTLogSourceJavaScript, nil, nil, message);
|
|
}
|
|
}
|
|
}
|