diff --git a/RNTester/RNTesterUnitTests/RCTComponentPropsTests.m b/RNTester/RNTesterUnitTests/RCTComponentPropsTests.m index 4525938cdd..759c2e3b42 100644 --- a/RNTester/RNTesterUnitTests/RCTComponentPropsTests.m +++ b/RNTester/RNTesterUnitTests/RCTComponentPropsTests.m @@ -11,6 +11,8 @@ #import #import +#import +#import #import #import #import @@ -26,6 +28,8 @@ viewName:(NSString *)viewName props:(NSDictionary *)props; +@property (nonatomic, copy, readonly) NSMutableDictionary *shadowViewRegistry; + @end @interface RCTPropsTestView : UIView @@ -74,6 +78,7 @@ RCT_CUSTOM_VIEW_PROPERTY(customProp, NSString, RCTPropsTestView) @implementation RCTComponentPropsTests { RCTBridge *_bridge; + NSNumber *_rootViewReactTag; } - (void)setUp @@ -84,6 +89,16 @@ RCT_CUSTOM_VIEW_PROPERTY(customProp, NSString, RCTPropsTestView) _bridge = [[RCTBridge alloc] initWithBundleURL:[bundle URLForResource:@"RNTesterUnitTestsBundle" withExtension:@"js"] moduleProvider:nil launchOptions:nil]; + + _rootViewReactTag = @1; + RCTUIManager *uiManager = _bridge.uiManager; + + dispatch_async(uiManager.methodQueue, ^{ + RCTRootShadowView *rootShadowView = [RCTRootShadowView new]; + rootShadowView.reactTag = self->_rootViewReactTag; + uiManager.shadowViewRegistry[rootShadowView.reactTag] = rootShadowView; + }); + RCT_RUN_RUNLOOP_WHILE(_bridge.isLoading); } @@ -97,7 +112,7 @@ RCT_CUSTOM_VIEW_PROPERTY(customProp, NSString, RCTPropsTestView) @"customProp": @"Goodbye"}; dispatch_async(uiManager.methodQueue, ^{ - [uiManager createView:@2 viewName:@"RCTPropsTestView" rootTag:nil props:props]; + [uiManager createView:@2 viewName:@"RCTPropsTestView" rootTag:self->_rootViewReactTag props:props]; [uiManager addUIBlock:^(__unused RCTUIManager *_uiManager, NSDictionary *viewRegistry) { view = (RCTPropsTestView *)viewRegistry[@2]; XCTAssertEqual(view.integerProp, 58); @@ -126,7 +141,7 @@ RCT_CUSTOM_VIEW_PROPERTY(customProp, NSString, RCTPropsTestView) @"customProp": [NSNull null]}; dispatch_async(uiManager.methodQueue, ^{ - [uiManager createView:@2 viewName:@"RCTPropsTestView" rootTag:nil props:props]; + [uiManager createView:@2 viewName:@"RCTPropsTestView" rootTag:self->_rootViewReactTag props:props]; [uiManager updateView:@2 viewName:@"RCTPropsTestView" props:resetProps]; [uiManager addUIBlock:^(__unused RCTUIManager *_uiManager, NSDictionary *viewRegistry) { view = (RCTPropsTestView *)viewRegistry[@2]; @@ -149,7 +164,7 @@ RCT_CUSTOM_VIEW_PROPERTY(customProp, NSString, RCTPropsTestView) NSDictionary *resetProps = @{@"backgroundColor": [NSNull null]}; dispatch_async(uiManager.methodQueue, ^{ - [uiManager createView:@2 viewName:@"RCTView" rootTag:nil props:props]; + [uiManager createView:@2 viewName:@"RCTView" rootTag:self->_rootViewReactTag props:props]; [uiManager addUIBlock:^(__unused RCTUIManager *_uiManager, NSDictionary *viewRegistry) { view = (RCTView *)viewRegistry[@2]; XCTAssertEqualObjects(view.backgroundColor, [RCTConvert UIColor:@0xffffffff]); diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index 4a6724c41c..4d57ef3bf4 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -33,7 +33,7 @@ #import "RCTRootShadowView.h" #import "RCTRootViewInternal.h" #import "RCTScrollableProtocol.h" -#import "RCTShadowView+Hierarchy.h" +#import "RCTShadowView+Internal.h" #import "RCTShadowView.h" #import "RCTUIManagerObserverCoordinator.h" #import "RCTUtils.h" @@ -939,7 +939,7 @@ RCT_EXPORT_METHOD(manageChildren:(nonnull NSNumber *)containerTag RCT_EXPORT_METHOD(createView:(nonnull NSNumber *)reactTag viewName:(NSString *)viewName - rootTag:(__unused NSNumber *)rootTag + rootTag:(nonnull NSNumber *)rootTag props:(NSDictionary *)props) { RCTComponentData *componentData = _componentDataByName[viewName]; @@ -952,6 +952,10 @@ RCT_EXPORT_METHOD(createView:(nonnull NSNumber *)reactTag if (shadowView) { [componentData setProps:props forShadowView:shadowView]; _shadowViewRegistry[reactTag] = shadowView; + RCTShadowView *rootView = _shadowViewRegistry[rootTag]; + RCTAssert([rootView isKindOfClass:[RCTRootShadowView class]], + @"Given `rootTag` (%@) does not correspond to a valid root shadow view instance.", rootTag); + shadowView.rootView = (RCTRootShadowView *)rootView; } // Shadow view is the source of truth for background color this is a little diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj index 04af6ee525..39fb803983 100644 --- a/React/React.xcodeproj/project.pbxproj +++ b/React/React.xcodeproj/project.pbxproj @@ -203,8 +203,6 @@ 14F7A0F01BDA714B003C6C10 /* RCTFPSGraph.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F7A0EF1BDA714B003C6C10 /* RCTFPSGraph.m */; }; 191E3EBE1C29D9AF00C180A6 /* RCTRefreshControlManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 191E3EBD1C29D9AF00C180A6 /* RCTRefreshControlManager.m */; }; 191E3EC11C29DC3800C180A6 /* RCTRefreshControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 191E3EC01C29DC3800C180A6 /* RCTRefreshControl.m */; }; - 19F0AD721F1DE7C400E4949F /* RCTShadowView+Hierarchy.h in Headers */ = {isa = PBXBuildFile; fileRef = 19F0AD701F1DE7C400E4949F /* RCTShadowView+Hierarchy.h */; }; - 19F0AD731F1DE7C400E4949F /* RCTShadowView+Hierarchy.m in Sources */ = {isa = PBXBuildFile; fileRef = 19F0AD711F1DE7C400E4949F /* RCTShadowView+Hierarchy.m */; }; 19F61BFA1E8495CD00571D81 /* bignum-dtoa.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 139D7E3A1E25C5A300323FB7 /* bignum-dtoa.h */; }; 19F61BFB1E8495CD00571D81 /* bignum.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 139D7E3C1E25C5A300323FB7 /* bignum.h */; }; 19F61BFC1E8495CD00571D81 /* cached-powers.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 139D7E3E1E25C5A300323FB7 /* cached-powers.h */; }; @@ -1013,6 +1011,10 @@ 5960C1BE1F0804DF0066FD5B /* RCTLayoutAnimationGroup.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5960C1B31F0804A00066FD5B /* RCTLayoutAnimationGroup.h */; }; 5960C1BF1F0804F50066FD5B /* RCTLayoutAnimation.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5960C1B11F0804A00066FD5B /* RCTLayoutAnimation.h */; }; 5960C1C01F0804F50066FD5B /* RCTLayoutAnimationGroup.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5960C1B31F0804A00066FD5B /* RCTLayoutAnimationGroup.h */; }; + 597633361F4E021D005BE8A4 /* RCTShadowView+Internal.m in Sources */ = {isa = PBXBuildFile; fileRef = 597633341F4E021D005BE8A4 /* RCTShadowView+Internal.m */; }; + 597633371F4E021D005BE8A4 /* RCTShadowView+Internal.m in Sources */ = {isa = PBXBuildFile; fileRef = 597633341F4E021D005BE8A4 /* RCTShadowView+Internal.m */; }; + 597633381F4E021D005BE8A4 /* RCTShadowView+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 597633351F4E021D005BE8A4 /* RCTShadowView+Internal.h */; }; + 597633391F4E021D005BE8A4 /* RCTShadowView+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 597633351F4E021D005BE8A4 /* RCTShadowView+Internal.h */; }; 59A7B9FD1E577DBF0068EDBF /* RCTRootContentView.h in Headers */ = {isa = PBXBuildFile; fileRef = 59A7B9FB1E577DBF0068EDBF /* RCTRootContentView.h */; }; 59A7B9FE1E577DBF0068EDBF /* RCTRootContentView.m in Sources */ = {isa = PBXBuildFile; fileRef = 59A7B9FC1E577DBF0068EDBF /* RCTRootContentView.m */; }; 59B1EBC91EBD46250047B19B /* RCTShadowView+Layout.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 590D7BFB1EBD458B00D8A370 /* RCTShadowView+Layout.h */; }; @@ -1841,8 +1843,6 @@ 191E3EBF1C29DC3800C180A6 /* RCTRefreshControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRefreshControl.h; sourceTree = ""; }; 191E3EC01C29DC3800C180A6 /* RCTRefreshControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRefreshControl.m; sourceTree = ""; }; 19DED2281E77E29200F089BB /* systemJSCWrapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = systemJSCWrapper.cpp; sourceTree = ""; }; - 19F0AD701F1DE7C400E4949F /* RCTShadowView+Hierarchy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTShadowView+Hierarchy.h"; sourceTree = ""; }; - 19F0AD711F1DE7C400E4949F /* RCTShadowView+Hierarchy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTShadowView+Hierarchy.m"; sourceTree = ""; }; 27B958731E57587D0096647A /* JSBigString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSBigString.cpp; sourceTree = ""; }; 2D2A28131D9B038B00D4039D /* libReact.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libReact.a; sourceTree = BUILT_PRODUCTS_DIR; }; 352DCFEE1D19F4C20056D623 /* RCTI18nUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTI18nUtil.h; sourceTree = ""; }; @@ -1962,6 +1962,8 @@ 5960C1B21F0804A00066FD5B /* RCTLayoutAnimation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTLayoutAnimation.m; sourceTree = ""; }; 5960C1B31F0804A00066FD5B /* RCTLayoutAnimationGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTLayoutAnimationGroup.h; sourceTree = ""; }; 5960C1B41F0804A00066FD5B /* RCTLayoutAnimationGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTLayoutAnimationGroup.m; sourceTree = ""; }; + 597633341F4E021D005BE8A4 /* RCTShadowView+Internal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTShadowView+Internal.m"; sourceTree = ""; }; + 597633351F4E021D005BE8A4 /* RCTShadowView+Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTShadowView+Internal.h"; sourceTree = ""; }; 59A7B9FB1E577DBF0068EDBF /* RCTRootContentView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRootContentView.h; sourceTree = ""; }; 59A7B9FC1E577DBF0068EDBF /* RCTRootContentView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRootContentView.m; sourceTree = ""; }; 59EB6DB91EBD6FC90072A5E7 /* RCTUIManagerObserverCoordinator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTUIManagerObserverCoordinator.h; sourceTree = ""; }; @@ -2329,8 +2331,8 @@ 131B6AF31AF1093D00FFC3E0 /* RCTSegmentedControlManager.m */, 13E0674B1A70F44B002CDEE1 /* RCTShadowView.h */, 13E0674C1A70F44B002CDEE1 /* RCTShadowView.m */, - 19F0AD701F1DE7C400E4949F /* RCTShadowView+Hierarchy.h */, - 19F0AD711F1DE7C400E4949F /* RCTShadowView+Hierarchy.m */, + 597633351F4E021D005BE8A4 /* RCTShadowView+Internal.h */, + 597633341F4E021D005BE8A4 /* RCTShadowView+Internal.m */, 590D7BFB1EBD458B00D8A370 /* RCTShadowView+Layout.h */, 590D7BFC1EBD458B00D8A370 /* RCTShadowView+Layout.m */, 13AF20431AE707F8005F5298 /* RCTSlider.h */, @@ -2776,6 +2778,7 @@ 3D302F371DF828F800D6DDAE /* RCTEventDispatcher.h in Headers */, 3D302F381DF828F800D6DDAE /* RCTFrameUpdate.h in Headers */, 3D302F391DF828F800D6DDAE /* RCTImageSource.h in Headers */, + 597633391F4E021D005BE8A4 /* RCTShadowView+Internal.h in Headers */, 3D302F3A1DF828F800D6DDAE /* RCTInvalidating.h in Headers */, 3D302F3B1DF828F800D6DDAE /* RCTJavaScriptExecutor.h in Headers */, 3D302F3C1DF828F800D6DDAE /* RCTJavaScriptLoader.h in Headers */, @@ -3049,6 +3052,7 @@ 3D80DA271DF820620028D040 /* RCTConvert.h in Headers */, 3D80DA281DF820620028D040 /* RCTDefines.h in Headers */, 3D80DA291DF820620028D040 /* RCTDisplayLink.h in Headers */, + 597633381F4E021D005BE8A4 /* RCTShadowView+Internal.h in Headers */, 3D80DA2A1DF820620028D040 /* RCTErrorCustomizer.h in Headers */, 3D80DA2B1DF820620028D040 /* RCTErrorInfo.h in Headers */, 1384E2081E806D4E00545659 /* RCTNativeModule.h in Headers */, @@ -3152,7 +3156,6 @@ 657734901EE8354A00A0E9EA /* RCTInspectorPackagerConnection.h in Headers */, 3D7BFD1D1EA8E351008DFB7A /* RCTPackagerConnection.h in Headers */, 3D80DA7F1DF820620028D040 /* RCTScrollView.h in Headers */, - 19F0AD721F1DE7C400E4949F /* RCTShadowView+Hierarchy.h in Headers */, 3D80DA801DF820620028D040 /* RCTScrollViewManager.h in Headers */, 3D80DA811DF820620028D040 /* RCTSegmentedControl.h in Headers */, C6827DF61EF17CCC00D66BEF /* RCTJSEnvironment.h in Headers */, @@ -3659,6 +3662,7 @@ 2D3B5EA51D9B08C700451313 /* RCTRootView.m in Sources */, 13134C871E296B2A00B9F3CB /* RCTCxxBridge.mm in Sources */, CF2731C31E7B8DF30044CA4F /* RCTDeviceInfo.m in Sources */, + 597633371F4E021D005BE8A4 /* RCTShadowView+Internal.m in Sources */, 2D3B5EB11D9B090100451313 /* RCTAppState.m in Sources */, 1384E20B1E806D5B00545659 /* RCTNativeModule.mm in Sources */, 2D3B5EC21D9B093B00451313 /* RCTProfile.m in Sources */, @@ -3855,6 +3859,7 @@ buildActionMask = 2147483647; files = ( 13134C9A1E296B2A00B9F3CB /* RCTCxxMethod.mm in Sources */, + 597633361F4E021D005BE8A4 /* RCTShadowView+Internal.m in Sources */, 59FBEFB61E46D91C0095D885 /* RCTScrollContentViewManager.m in Sources */, 13723B501A82FD3C00F88898 /* RCTStatusBarManager.m in Sources */, 000E6CEB1AB0E980000CDF4D /* RCTSourceCode.m in Sources */, @@ -3914,7 +3919,6 @@ 13B080261A694A8400A75B9A /* RCTWrapperViewController.m in Sources */, 13B080051A6947C200A75B9A /* RCTScrollView.m in Sources */, A2440AA31DF8D854006E7BFC /* RCTReloadCommand.m in Sources */, - 19F0AD731F1DE7C400E4949F /* RCTShadowView+Hierarchy.m in Sources */, 3DF1BE821F26576400068F1A /* JSCTracing.cpp in Sources */, 6577348F1EE8354A00A0E9EA /* RCTInspector.mm in Sources */, E9B20B7B1B500126007A2DA7 /* RCTAccessibilityManager.m in Sources */, diff --git a/React/Views/RCTShadowView+Hierarchy.h b/React/Views/RCTShadowView+Internal.h similarity index 68% rename from React/Views/RCTShadowView+Hierarchy.h rename to React/Views/RCTShadowView+Internal.h index be644c9531..cf2d3bf5a2 100644 --- a/React/Views/RCTShadowView+Hierarchy.h +++ b/React/Views/RCTShadowView+Internal.h @@ -6,11 +6,15 @@ * 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 + +#import + #import -@interface RCTShadowView (Hierarchy) +@class RCTRootShadowView; -@property (nonatomic, readonly) RCTRootShadowView *rootView; +@interface RCTShadowView (Internal) + +@property (nonatomic, weak, readwrite) RCTRootShadowView *rootView; @end diff --git a/React/Views/RCTShadowView+Hierarchy.m b/React/Views/RCTShadowView+Internal.m similarity index 52% rename from React/Views/RCTShadowView+Hierarchy.m rename to React/Views/RCTShadowView+Internal.m index d0b05c8a9f..09b74ca2e2 100644 --- a/React/Views/RCTShadowView+Hierarchy.m +++ b/React/Views/RCTShadowView+Internal.m @@ -6,18 +6,21 @@ * 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 "RCTShadowView+Hierarchy.h" -@implementation RCTShadowView (Hierarchy) +#import "RCTShadowView+Layout.h" -- (nullable RCTRootShadowView *)rootView +@interface RCTShadowView () { - RCTShadowView *view = self; - while (view != nil && ![view isKindOfClass:[RCTRootShadowView class]]) { - view = view.superview; - } - - return (RCTRootShadowView *)view; + __weak RCTRootShadowView *_rootView; +} + +@end + +@implementation RCTShadowView (Internal) + +- (void)setRootView:(RCTRootShadowView *)rootView +{ + _rootView = rootView; } @end diff --git a/React/Views/RCTShadowView.h b/React/Views/RCTShadowView.h index 90f21c8635..8f34abdba7 100644 --- a/React/Views/RCTShadowView.h +++ b/React/Views/RCTShadowView.h @@ -13,6 +13,7 @@ #import #import +@class RCTRootShadowView; @class RCTSparseArray; typedef NS_ENUM(NSUInteger, RCTUpdateLifecycle) { @@ -50,6 +51,7 @@ typedef void (^RCTApplierBlock)(NSDictionary *viewRegistry - (void)insertReactSubview:(RCTShadowView *)subview atIndex:(NSInteger)atIndex NS_REQUIRES_SUPER; - (void)removeReactSubview:(RCTShadowView *)subview NS_REQUIRES_SUPER; +@property (nonatomic, weak, readonly) RCTRootShadowView *rootView; @property (nonatomic, weak, readonly) RCTShadowView *superview; @property (nonatomic, assign, readonly) YGNodeRef yogaNode; @property (nonatomic, copy) NSString *viewName;