mirror of
https://github.com/status-im/realm-js.git
synced 2025-01-10 14:25:58 +00:00
Make React reloads and testing more reliable
Changed where we wait on the previous JS thread, which ultimately makes it more reliable and no longer leak memory on reloads. Resolves #397
This commit is contained in:
parent
933e6070c5
commit
db1283255f
@ -79,8 +79,6 @@ extern "C" JSGlobalContextRef RealmReactGetJSGlobalContextForExecutor(id executo
|
|||||||
|
|
||||||
@implementation RealmReact {
|
@implementation RealmReact {
|
||||||
NSMutableDictionary *_eventHandlers;
|
NSMutableDictionary *_eventHandlers;
|
||||||
__weak NSThread *_currentJSThread;
|
|
||||||
__weak NSRunLoop *_currentJSRunLoop;
|
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
GCDWebServer *_webServer;
|
GCDWebServer *_webServer;
|
||||||
@ -261,17 +259,6 @@ RCT_REMAP_METHOD(emit, emitEvent:(NSString *)eventName withObject:(id)object) {
|
|||||||
// shutdown rpc if in chrome debug mode
|
// shutdown rpc if in chrome debug mode
|
||||||
[self shutdownRPC];
|
[self shutdownRPC];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// block until JS thread exits
|
|
||||||
NSRunLoop *runLoop = _currentJSRunLoop;
|
|
||||||
if (runLoop) {
|
|
||||||
CFRunLoopStop([runLoop getCFRunLoop]);
|
|
||||||
while (_currentJSThread && !_currentJSThread.finished) {
|
|
||||||
[NSThread sleepForTimeInterval:0.01];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
realm::_impl::RealmCoordinator::clear_all_caches();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc {
|
- (void)dealloc {
|
||||||
@ -296,15 +283,24 @@ RCT_REMAP_METHOD(emit, emitEvent:(NSString *)eventName withObject:(id)object) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
__weak __typeof__(self) weakSelf = self;
|
__weak __typeof__(self) weakSelf = self;
|
||||||
|
__weak __typeof__(executor) weakExecutor = executor;
|
||||||
|
|
||||||
[executor executeBlockOnJavaScriptQueue:^{
|
[executor executeBlockOnJavaScriptQueue:^{
|
||||||
__typeof__(self) self = weakSelf;
|
__typeof__(self) self = weakSelf;
|
||||||
if (!self) {
|
__typeof__(executor) executor = weakExecutor;
|
||||||
|
if (!self || !executor) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self->_currentJSThread = [NSThread currentThread];
|
// Make sure the previous JS thread is completely finished before continuing.
|
||||||
self->_currentJSRunLoop = [NSRunLoop currentRunLoop];
|
static __weak NSThread *s_currentJSThread;
|
||||||
|
while (s_currentJSThread && !s_currentJSThread.finished) {
|
||||||
|
[NSThread sleepForTimeInterval:0.1];
|
||||||
|
}
|
||||||
|
s_currentJSThread = [NSThread currentThread];
|
||||||
|
|
||||||
|
// Close all cached Realms from the previous JS thread.
|
||||||
|
realm::_impl::RealmCoordinator::clear_all_caches();
|
||||||
|
|
||||||
JSGlobalContextRef ctx = RealmReactGetJSGlobalContextForExecutor(executor, true);
|
JSGlobalContextRef ctx = RealmReactGetJSGlobalContextForExecutor(executor, true);
|
||||||
RJSInitializeInContext(ctx);
|
RJSInitializeInContext(ctx);
|
||||||
|
@ -78,23 +78,26 @@ extern NSMutableArray *RCTGetModuleClasses(void);
|
|||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
RCTBridge *bridge = [RCTBridge currentBridge];
|
@autoreleasepool {
|
||||||
if (!bridge.valid) {
|
RCTBridge *bridge = [RCTBridge currentBridge];
|
||||||
[self waitForNotification:RCTJavaScriptDidLoadNotification];
|
|
||||||
bridge = [RCTBridge currentBridge];
|
if (!bridge.valid) {
|
||||||
|
[self waitForNotification:RCTJavaScriptDidLoadNotification];
|
||||||
|
bridge = [RCTBridge currentBridge];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bridge.executorClass != executorClass) {
|
||||||
|
bridge.executorClass = executorClass;
|
||||||
|
|
||||||
|
RCTBridge *parentBridge = [bridge valueForKey:@"parentBridge"];
|
||||||
|
[parentBridge invalidate];
|
||||||
|
[parentBridge setUp];
|
||||||
|
|
||||||
|
return [self currentBridge];
|
||||||
|
}
|
||||||
|
|
||||||
|
return bridge;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bridge.executorClass != executorClass) {
|
|
||||||
bridge.executorClass = executorClass;
|
|
||||||
|
|
||||||
RCTBridge *parentBridge = [bridge valueForKey:@"parentBridge"];
|
|
||||||
[parentBridge invalidate];
|
|
||||||
[parentBridge setUp];
|
|
||||||
|
|
||||||
return [self currentBridge];
|
|
||||||
}
|
|
||||||
|
|
||||||
return bridge;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id<RCTJavaScriptExecutor>)currentExecutor {
|
+ (id<RCTJavaScriptExecutor>)currentExecutor {
|
||||||
@ -102,37 +105,39 @@ extern NSMutableArray *RCTGetModuleClasses(void);
|
|||||||
}
|
}
|
||||||
|
|
||||||
+ (XCTestSuite *)defaultTestSuite {
|
+ (XCTestSuite *)defaultTestSuite {
|
||||||
XCTestSuite *suite = [super defaultTestSuite];
|
@autoreleasepool {
|
||||||
id<RCTJavaScriptExecutor> executor = [self currentExecutor];
|
XCTestSuite *suite = [super defaultTestSuite];
|
||||||
|
id<RCTJavaScriptExecutor> executor = [self currentExecutor];
|
||||||
|
|
||||||
|
// The executor may be nil if the executorClass was not found (i.e. release build).
|
||||||
|
if (!executor) {
|
||||||
|
return suite;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Remove this nonsense once the crashes go away when a test fails!
|
||||||
|
JSGlobalContextRef ctx = RealmReactGetJSGlobalContextForExecutor(executor, false);
|
||||||
|
if (ctx) {
|
||||||
|
JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions(ctx, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
NSDictionary *testCaseNames = [self waitForEvent:@"realm-test-names"];
|
||||||
|
NSAssert(testCaseNames.count, @"No test names were provided by the JS");
|
||||||
|
|
||||||
|
NSString *nameSuffix = [self classNameSuffix];
|
||||||
|
if (nameSuffix.length) {
|
||||||
|
NSMutableDictionary *renamedTestCaseNames = [[NSMutableDictionary alloc] init];
|
||||||
|
for (NSString *name in testCaseNames) {
|
||||||
|
renamedTestCaseNames[[name stringByAppendingString:nameSuffix]] = testCaseNames[name];
|
||||||
|
}
|
||||||
|
testCaseNames = renamedTestCaseNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (XCTestSuite *testSuite in [self testSuitesFromDictionary:testCaseNames]) {
|
||||||
|
[suite addTest:testSuite];
|
||||||
|
}
|
||||||
|
|
||||||
// The executor may be nil if the executorClass was not found (i.e. release build).
|
|
||||||
if (!executor) {
|
|
||||||
return suite;
|
return suite;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Remove this nonsense once the crashes go away when a test fails!
|
|
||||||
JSGlobalContextRef ctx = RealmReactGetJSGlobalContextForExecutor(executor, false);
|
|
||||||
if (ctx) {
|
|
||||||
JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions(ctx, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
NSDictionary *testCaseNames = [self waitForEvent:@"realm-test-names"];
|
|
||||||
NSAssert(testCaseNames.count, @"No test names were provided by the JS");
|
|
||||||
|
|
||||||
NSString *nameSuffix = [self classNameSuffix];
|
|
||||||
if (nameSuffix.length) {
|
|
||||||
NSMutableDictionary *renamedTestCaseNames = [[NSMutableDictionary alloc] init];
|
|
||||||
for (NSString *name in testCaseNames) {
|
|
||||||
renamedTestCaseNames[[name stringByAppendingString:nameSuffix]] = testCaseNames[name];
|
|
||||||
}
|
|
||||||
testCaseNames = renamedTestCaseNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (XCTestSuite *testSuite in [self testSuitesFromDictionary:testCaseNames]) {
|
|
||||||
[suite addTest:testSuite];
|
|
||||||
}
|
|
||||||
|
|
||||||
return suite;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSNotification *)waitForNotification:(NSString *)notificationName {
|
+ (NSNotification *)waitForNotification:(NSString *)notificationName {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user