From 0ffb2d36ebfa6fded818847738e8eb0e184dcaf5 Mon Sep 17 00:00:00 2001 From: Tadeu Zagallo Date: Tue, 7 Jul 2015 18:23:58 -0700 Subject: [PATCH] [ReactNative] Fix crash when reload during profile Summary: Fixes #1642 When reloading during profiling, the profile wouldn't unhook from the instance being deallocated. --- React/Base/RCTBatchedBridge.m | 12 ++++++++++++ React/Base/RCTProfile.h | 13 +++++++++++++ React/Base/RCTProfile.m | 8 +++++--- React/Views/RCTNavigator.m | 2 +- 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m index 9b77ad466..569c7f779 100644 --- a/React/Base/RCTBatchedBridge.m +++ b/React/Base/RCTBatchedBridge.m @@ -106,6 +106,13 @@ id RCTGetLatestExecutor(void) */ [self registerModules]; + /** + * If currently profiling, hook into the current instance + */ + if (RCTProfileIsProfiling()) { + RCTProfileHookModules(self); + } + /** * Start the application script */ @@ -364,8 +371,13 @@ RCT_NOT_IMPLEMENTED(-initWithBundleURL:(__unused NSURL *)bundleURL } moduleData.queue = nil; } + dispatch_group_notify(group, dispatch_get_main_queue(), ^{ [_javaScriptExecutor executeBlockOnJavaScriptQueue:^{ + if (RCTProfileIsProfiling()) { + RCTProfileUnhookModules(self); + } + [_jsDisplayLink invalidate]; _jsDisplayLink = nil; diff --git a/React/Base/RCTProfile.h b/React/Base/RCTProfile.h index 469a81552..66cf40bf4 100644 --- a/React/Base/RCTProfile.h +++ b/React/Base/RCTProfile.h @@ -103,6 +103,16 @@ RCT_EXTERN void RCTProfileImmediateEvent(NSString *, NSTimeInterval , NSString * RCTProfileEndEvent([NSString stringWithFormat:@"[%@ %@]", NSStringFromClass([self class]), NSStringFromSelector(_cmd)], category, arguments); \ } +/** + * Hook into a bridge instance to log all bridge module's method calls + */ +RCT_EXTERN void RCTProfileHookModules(RCTBridge *); + +/** + * Unhook from a given bridge instance's modules + */ +RCT_EXTERN void RCTProfileUnhookModules(RCTBridge *); + #else #define RCTProfileBeginFlowEvent() @@ -125,4 +135,7 @@ RCT_EXTERN void RCTProfileImmediateEvent(NSString *, NSTimeInterval , NSString * #define RCTProfileBlock(block, ...) block +#define RCTProfileHookModules(...) +#define RCTProfileUnhookModules(...) + #endif diff --git a/React/Base/RCTProfile.m b/React/Base/RCTProfile.m index 62a17fe7b..4eeaf3e9d 100644 --- a/React/Base/RCTProfile.m +++ b/React/Base/RCTProfile.m @@ -144,14 +144,17 @@ static IMP RCTProfileMsgForward(NSObject *self, SEL selector) return imp; } -static void RCTProfileHookModules(RCTBridge *); -static void RCTProfileHookModules(RCTBridge *bridge) +void RCTProfileHookModules(RCTBridge *bridge) { for (RCTModuleData *moduleData in [bridge valueForKey:@"_modules"]) { [moduleData dispatchBlock:^{ Class moduleClass = moduleData.cls; Class proxyClass = objc_allocateClassPair(moduleClass, RCTProfileProxyClassName(moduleClass), 0); + if (!proxyClass) { + return; + } + unsigned int methodCount; Method *methods = class_copyMethodList(moduleClass, &methodCount); for (NSUInteger i = 0; i < methodCount; i++) { @@ -185,7 +188,6 @@ static void RCTProfileHookModules(RCTBridge *bridge) } } -void RCTProfileUnhookModules(RCTBridge *); void RCTProfileUnhookModules(RCTBridge *bridge) { for (RCTModuleData *moduleData in [bridge valueForKey:@"_modules"]) { diff --git a/React/Views/RCTNavigator.m b/React/Views/RCTNavigator.m index 63e3d8023..ff91b0b54 100644 --- a/React/Views/RCTNavigator.m +++ b/React/Views/RCTNavigator.m @@ -436,7 +436,7 @@ RCT_NOT_IMPLEMENTED(-initWithCoder:(NSCoder *)aDecoder) */ - (UIView *)reactSuperview { - RCTAssert(self.superview != nil, @"put reactNavSuperviewLink back"); + RCTAssert(!_bridge.isValid || self.superview != nil, @"put reactNavSuperviewLink back"); return self.superview ? self.superview : self.reactNavSuperviewLink; }