diff --git a/Libraries/AppRegistry/AppRegistry.js b/Libraries/AppRegistry/AppRegistry.js index f36f88132..157cbaa37 100644 --- a/Libraries/AppRegistry/AppRegistry.js +++ b/Libraries/AppRegistry/AppRegistry.js @@ -74,7 +74,9 @@ var AppRegistry = { ); invariant( runnables[appKey] && runnables[appKey].run, - 'Application ' + appKey + ' has not been registered.' + 'Application ' + appKey + ' has not been registered. This ' + + 'is either due to a require() error during initialization ' + + 'or failure to call AppRegistry.registerComponent.' ); runnables[appKey].run(appParameters); }, diff --git a/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimers.js b/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimers.js index 6434541bb..72e75f813 100644 --- a/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimers.js +++ b/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimers.js @@ -60,14 +60,10 @@ var JSTimers = { var freeIndex = JSTimers._getFreeIndex(); JSTimersExecution.timerIDs[freeIndex] = newID; JSTimersExecution.callbacks[freeIndex] = function() { - var startTime = Date.now(); - var ret = func.apply(undefined, args); - var endTime = Date.now(); - RCTTiming.createTimer(newID, Math.max(0, duration - (endTime - startTime)), endTime, false); - return ret; + return func.apply(undefined, args); }; JSTimersExecution.types[freeIndex] = JSTimersExecution.Type.setInterval; - RCTTiming.createTimer(newID, duration, Date.now(), /** recurring */ false); + RCTTiming.createTimer(newID, duration, Date.now(), /** recurring */ true); return newID; }, diff --git a/Libraries/ReactNative/createReactNativeComponentClass.js b/Libraries/ReactNative/createReactNativeComponentClass.js index c821cfa75..65af58d5e 100644 --- a/Libraries/ReactNative/createReactNativeComponentClass.js +++ b/Libraries/ReactNative/createReactNativeComponentClass.js @@ -36,6 +36,7 @@ var createReactNativeComponentClass = function( }; Constructor.displayName = viewConfig.uiViewClassName; Constructor.prototype = new ReactNativeBaseComponent(viewConfig); + Constructor.prototype.constructor = Constructor; return Constructor; }; diff --git a/React/Executors/RCTContextExecutor.m b/React/Executors/RCTContextExecutor.m index f585edc10..3a2208739 100644 --- a/React/Executors/RCTContextExecutor.m +++ b/React/Executors/RCTContextExecutor.m @@ -66,7 +66,6 @@ { RCTJavaScriptContext *_context; NSThread *_javaScriptThread; - JSValueRef _undefined; } /** @@ -238,9 +237,6 @@ static NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError) JSContextGroupRelease(group); } - // Constant value used for comparison - _undefined = JSValueMakeUndefined(ctx); - strongSelf->_context = [[RCTJavaScriptContext alloc] initWithJSContext:ctx]; [strongSelf _addNativeHook:RCTNativeLoggingHook withName:"nativeLoggingHook"]; [strongSelf _addNativeHook:RCTNoop withName:"noop"]; @@ -312,7 +308,7 @@ static NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError) JSValueRef requireJSRef = JSObjectGetProperty(contextJSRef, globalObjectJSRef, requireNameJSStringRef, &errorJSRef); JSStringRelease(requireNameJSStringRef); - if (requireJSRef != NULL && requireJSRef != _undefined && errorJSRef == NULL) { + if (requireJSRef != NULL && !JSValueIsUndefined(contextJSRef, requireJSRef) && errorJSRef == NULL) { // get module JSStringRef moduleNameJSStringRef = JSStringCreateWithCFString((__bridge CFStringRef)name); diff --git a/React/Modules/RCTAppState.m b/React/Modules/RCTAppState.m index 8c46655c6..cf8f95910 100644 --- a/React/Modules/RCTAppState.m +++ b/React/Modules/RCTAppState.m @@ -48,17 +48,16 @@ RCT_EXPORT_MODULE() for (NSString *name in @[UIApplicationDidBecomeActiveNotification, UIApplicationDidEnterBackgroundNotification, UIApplicationDidFinishLaunchingNotification]) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAppStateDidChange) name:name object:nil]; - - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(handleMemoryWarning) - name:UIApplicationDidReceiveMemoryWarningNotification - object:nil]; } + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(handleMemoryWarning) + name:UIApplicationDidReceiveMemoryWarningNotification + object:nil]; } return self; } diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index 636df0406..127cbd9fc 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -197,7 +197,8 @@ static UIViewAnimationCurve UIViewAnimationCurveFromRCTAnimationType(RCTAnimatio NSMutableDictionary *_defaultViews; // Main thread only NSDictionary *_viewManagers; NSDictionary *_viewConfigs; - NSUInteger _rootTag; + + NSMutableSet *_bridgeTransactionListeners; } @synthesize bridge = _bridge; @@ -263,7 +264,8 @@ static NSDictionary *RCTViewConfigForModule(Class managerClass, NSString *viewNa // Internal resources _pendingUIBlocks = [[NSMutableArray alloc] init]; _rootViewTags = [[NSMutableSet alloc] init]; - _rootTag = 1; + + _bridgeTransactionListeners = [[NSMutableSet alloc] init]; } return self; } @@ -287,6 +289,7 @@ static NSDictionary *RCTViewConfigForModule(Class managerClass, NSString *viewNa _rootViewTags = nil; _shadowViewRegistry = nil; _viewRegistry = nil; + _bridgeTransactionListeners = nil; _bridge = nil; [_pendingUIBlocksLock lock]; @@ -397,6 +400,10 @@ static NSDictionary *RCTViewConfigForModule(Class managerClass, NSString *viewNa [(id)subview invalidate]; } registry[subview.reactTag] = nil; + + if (registry == _viewRegistry) { + [_bridgeTransactionListeners removeObject:subview]; + } }); } } @@ -482,7 +489,6 @@ static NSDictionary *RCTViewConfigForModule(Class managerClass, NSString *viewNa } // Perform layout (possibly animated) - NSNumber *rootViewTag = rootShadowView.reactTag; return ^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) { RCTResponseSenderBlock callback = self->_layoutAnimation.callback; __block NSInteger completionsCalled = 0; @@ -547,17 +553,11 @@ static NSDictionary *RCTViewConfigForModule(Class managerClass, NSString *viewNa } /** - * Enumerate all active (attached to a parent) views and call - * reactBridgeDidFinishTransaction on them if they implement it. - * TODO: this is quite inefficient. If this was handled via the - * ViewManager instead, it could be done more efficiently. + * TODO(tadeu): Remove it once and for all */ - UIView *rootView = _viewRegistry[rootViewTag]; - RCTTraverseViewNodes(rootView, ^(id view) { - if ([view respondsToSelector:@selector(reactBridgeDidFinishTransaction)]) { - [view reactBridgeDidFinishTransaction]; - } - }); + for (id node in _bridgeTransactionListeners) { + [node reactBridgeDidFinishTransaction]; + } }; } @@ -844,6 +844,10 @@ RCT_EXPORT_METHOD(createView:(NSNumber *)reactTag view.layer.allowsGroupOpacity = YES; // required for touch handling } RCTSetViewProps(props, view, uiManager->_defaultViews[viewName], manager); + + if ([view respondsToSelector:@selector(reactBridgeDidFinishTransaction)]) { + [uiManager->_bridgeTransactionListeners addObject:view]; + } } viewRegistry[reactTag] = view; }];