[ReactNative] Add RCTAssertThread and restrict -[UIManager addUIBlock:] to _shadowQueue
Summary: @public Add `RCTAssertThread` to `RCTAssert.h` for convenience when checking the current/queue, it accepts either a `NSString *`, `NSThread *` or `dispatch_queue_t` as the object to be checked Also add a check to `-[RCTUIManager addUIBlock:]` - There was a discussion on github (https://github.com/facebook/react-native/issues/1365) due to the weird behavior caused by calling it from a different thread/queue (it might be added after `batchDidComplete` has been called and will just be dispatched on the next call from JS to objc) Test Plan: Change `-[RCTAnimationExperimentalManager methodQueue]` to return `dispatch_get_main_queue()` and run the 2048 example, it should dispatch with a helpful message (screenshot on the comments)
This commit is contained in:
parent
c91e2eb567
commit
9062bda79b
|
@ -62,3 +62,31 @@ RCT_EXTERN RCTAssertFunction RCTGetAssertFunction(void);
|
|||
* assert info to an extra service without changing the default behavior.
|
||||
*/
|
||||
RCT_EXTERN void RCTAddAssertFunction(RCTAssertFunction assertFunction);
|
||||
|
||||
/**
|
||||
* Get the current thread's name (or the current queue, if in debug mode)
|
||||
*/
|
||||
RCT_EXTERN NSString *RCTCurrentThreadName(void);
|
||||
|
||||
/**
|
||||
* Convenience macro to assert which thread is currently running (DEBUG mode only)
|
||||
*/
|
||||
#if DEBUG
|
||||
|
||||
#define RCTAssertThread(thread, format...) \
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") \
|
||||
RCTAssert( \
|
||||
[(id)thread isKindOfClass:[NSString class]] ? \
|
||||
[RCTCurrentThreadName() isEqualToString:(NSString *)thread] : \
|
||||
[(id)thread isKindOfClass:[NSThread class]] ? \
|
||||
[NSThread currentThread] == (NSThread *)thread : \
|
||||
dispatch_get_current_queue() == (dispatch_queue_t)thread, \
|
||||
format); \
|
||||
_Pragma("clang diagnostic pop")
|
||||
|
||||
#else
|
||||
|
||||
#define RCTAssertThread(thread, format...)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -60,3 +60,20 @@ void RCTAddAssertFunction(RCTAssertFunction assertFunction)
|
|||
RCTCurrentAssertFunction = assertFunction;
|
||||
}
|
||||
}
|
||||
|
||||
NSString *RCTCurrentThreadName(void)
|
||||
{
|
||||
NSThread *thread = [NSThread currentThread];
|
||||
NSString *threadName = [thread isMainThread] ? @"main" : thread.name;
|
||||
if (threadName.length == 0) {
|
||||
#if DEBUG // This is DEBUG not RCT_DEBUG because it *really* must not ship in RC
|
||||
#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
|
||||
}
|
||||
return threadName;
|
||||
}
|
||||
|
|
|
@ -42,18 +42,12 @@ typedef void (^RCTLogFunction)(
|
|||
NSString *message
|
||||
);
|
||||
|
||||
/**
|
||||
* Get a given thread's name (or the current queue, if in debug mode)
|
||||
*/
|
||||
RCT_EXTERN NSString *RCTThreadName(NSThread *);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
RCT_EXTERN NSString *RCTFormatLog(
|
||||
NSDate *timestamp,
|
||||
NSThread *thread,
|
||||
RCTLogLevel level,
|
||||
NSString *fileName,
|
||||
NSNumber *lineNumber,
|
||||
|
|
|
@ -53,7 +53,7 @@ RCTLogFunction RCTDefaultLogFunction = ^(
|
|||
)
|
||||
{
|
||||
NSString *log = RCTFormatLog(
|
||||
[NSDate date], [NSThread currentThread], level, fileName, lineNumber, message
|
||||
[NSDate date], level, fileName, lineNumber, message
|
||||
);
|
||||
fprintf(stderr, "%s\n", log.UTF8String);
|
||||
fflush(stderr);
|
||||
|
@ -99,25 +99,8 @@ void RCTPerformBlockWithLogPrefix(void (^block)(void), NSString *prefix)
|
|||
[prefixStack removeLastObject];
|
||||
}
|
||||
|
||||
NSString *RCTThreadName(NSThread *thread)
|
||||
{
|
||||
NSString *threadName = [thread isMainThread] ? @"main" : thread.name;
|
||||
if (threadName.length == 0) {
|
||||
#if DEBUG // This is DEBUG not RCT_DEBUG because it *really* must not ship in RC
|
||||
#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
|
||||
}
|
||||
return threadName;
|
||||
}
|
||||
|
||||
NSString *RCTFormatLog(
|
||||
NSDate *timestamp,
|
||||
NSThread *thread,
|
||||
RCTLogLevel level,
|
||||
NSString *fileName,
|
||||
NSNumber *lineNumber,
|
||||
|
@ -137,9 +120,9 @@ NSString *RCTFormatLog(
|
|||
if (level) {
|
||||
[log appendFormat:@"[%s]", RCTLogLevels[level - 1]];
|
||||
}
|
||||
if (thread) {
|
||||
[log appendFormat:@"[tid:%@]", RCTThreadName(thread)];
|
||||
}
|
||||
|
||||
[log appendFormat:@"[tid:%@]", RCTCurrentThreadName()];
|
||||
|
||||
if (fileName) {
|
||||
fileName = [fileName lastPathComponent];
|
||||
if (lineNumber) {
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RCTAssert.h"
|
||||
#import "RCTDefines.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTUtils.h"
|
||||
|
||||
#if RCT_DEV
|
||||
|
@ -43,7 +43,7 @@ NSLock *_RCTProfileLock;
|
|||
#define RCTProfileAddEvent(type, props...) \
|
||||
[RCTProfileInfo[type] addObject:@{ \
|
||||
@"pid": @([[NSProcessInfo processInfo] processIdentifier]), \
|
||||
@"tid": RCTThreadName([NSThread currentThread]), \
|
||||
@"tid": RCTCurrentThreadName(), \
|
||||
props \
|
||||
}];
|
||||
|
||||
|
|
|
@ -390,6 +390,10 @@ static NSDictionary *RCTViewConfigForModule(Class managerClass, NSString *viewNa
|
|||
|
||||
- (void)addUIBlock:(RCTViewManagerUIBlock)block
|
||||
{
|
||||
RCTAssertThread(_shadowQueue,
|
||||
@"-[RCTUIManager addUIBlock:] should only be called from the "
|
||||
"UIManager's _shadowQueue (it may be accessed via `bridge.uiManager.methodQueue`)");
|
||||
|
||||
if (!self.isValid) {
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue