Skip to content

Commit 56ddace

Browse files
NickGerlemanfacebook-github-bot
authored andcommitted
Deterministic onLayout event ordering for iOS Paper (#40748)
Summary: Pull Request resolved: #40748 The ordering of `onLayout` events is non-deterministic on iOS Paper, due to nodes being added to an `NSHashTable` before iteration, instead of an ordered collection. We don't do any lookups on the collection, so I think this was chosen over `NSMutableArray` for the sake of `[NSHashTable weakObjectsHashTable]`, to avoid retain/release. Using a collection which does retain/release seems to cause a crash due to double release or similar, so those semantics seem intentional (though I'm not super familiar with the model here). We can replicate the memory semantics with ordering by using `NSPointerArray` (which is unfortunately not parameterized). This change does that, so we get consistently top-down layout events (matching Fabric, and Android Paper as of D49627996). This lets us use multiple layout events to calculate right/bottom edge insets deterministically. Changelog: [iOS][Changed] - Deterministic onLayout event ordering for iOS Paper Reviewed By: luluwu2032 Differential Revision: D50093411 fbshipit-source-id: f6a9d5c973b97aede879baa8b952cc1be2447f28
1 parent 5c2ec55 commit 56ddace

File tree

8 files changed

+9
-9
lines changed

8 files changed

+9
-9
lines changed

packages/react-native/React/Base/Surface/RCTSurfaceRootShadowView.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@
2727
*/
2828
@property (nonatomic, assign) YGDirection baseDirection;
2929

30-
- (void)layoutWithAffectedShadowViews:(NSHashTable<RCTShadowView *> *)affectedShadowViews;
30+
- (void)layoutWithAffectedShadowViews:(NSPointerArray *)affectedShadowViews;
3131

3232
@end

packages/react-native/React/Base/Surface/RCTSurfaceRootShadowView.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ - (void)insertReactSubview:(RCTShadowView *)subview atIndex:(NSInteger)atIndex
4141
}
4242
}
4343

44-
- (void)layoutWithAffectedShadowViews:(NSHashTable<RCTShadowView *> *)affectedShadowViews
44+
- (void)layoutWithAffectedShadowViews:(NSPointerArray *)affectedShadowViews
4545
{
4646
NSHashTable<NSString *> *other = [NSHashTable new];
4747

packages/react-native/React/Modules/RCTUIManager.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,7 @@ - (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTRootShadowView *
534534
{
535535
RCTAssertUIManagerQueue();
536536

537-
NSHashTable<RCTShadowView *> *affectedShadowViews = [NSHashTable weakObjectsHashTable];
537+
NSPointerArray *affectedShadowViews = [NSPointerArray weakObjectsPointerArray];
538538
[rootShadowView layoutWithAffectedShadowViews:affectedShadowViews];
539539

540540
if (!affectedShadowViews.count) {

packages/react-native/React/Views/RCTLayout.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ typedef struct CG_BOXABLE RCTLayoutMetrics RCTLayoutMetrics;
3131

3232
struct RCTLayoutContext {
3333
CGPoint absolutePosition;
34-
__unsafe_unretained NSHashTable<RCTShadowView *> *_Nonnull affectedShadowViews;
34+
__unsafe_unretained NSPointerArray *_Nonnull affectedShadowViews;
3535
__unsafe_unretained NSHashTable<NSString *> *_Nonnull other;
3636
};
3737
typedef struct CG_BOXABLE RCTLayoutContext RCTLayoutContext;

packages/react-native/React/Views/RCTRootShadowView.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,6 @@
2929
*/
3030
@property (nonatomic, assign) YGDirection baseDirection;
3131

32-
- (void)layoutWithAffectedShadowViews:(NSHashTable<RCTShadowView *> *)affectedShadowViews;
32+
- (void)layoutWithAffectedShadowViews:(NSPointerArray *)affectedShadowViews;
3333

3434
@end

packages/react-native/React/Views/RCTRootShadowView.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ - (instancetype)init
2323
return self;
2424
}
2525

26-
- (void)layoutWithAffectedShadowViews:(NSHashTable<RCTShadowView *> *)affectedShadowViews
26+
- (void)layoutWithAffectedShadowViews:(NSPointerArray *)affectedShadowViews
2727
{
2828
NSHashTable<NSString *> *other = [NSHashTable new];
2929

packages/react-native/React/Views/RCTShadowView.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ - (void)layoutWithMetrics:(RCTLayoutMetrics)layoutMetrics layoutContext:(RCTLayo
304304
{
305305
if (!RCTLayoutMetricsEqualToLayoutMetrics(self.layoutMetrics, layoutMetrics)) {
306306
self.layoutMetrics = layoutMetrics;
307-
[layoutContext.affectedShadowViews addObject:self];
307+
[layoutContext.affectedShadowViews addPointer:((__bridge void *)self)];
308308
}
309309
}
310310

packages/rn-tester/RNTesterUnitTests/RCTShadowViewTests.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ - (void)testApplyingLayoutRecursivelyToShadowView
8484
[self.parentView insertReactSubview:mainView atIndex:1];
8585
[self.parentView insertReactSubview:footerView atIndex:2];
8686

87-
[self.parentView layoutWithAffectedShadowViews:[NSHashTable weakObjectsHashTable]];
87+
[self.parentView layoutWithAffectedShadowViews:[NSPointerArray weakObjectsPointerArray]];
8888

8989
XCTAssertTrue(
9090
CGRectEqualToRect([self.parentView measureLayoutRelativeToAncestor:self.parentView], CGRectMake(0, 0, 440, 440)));
@@ -187,7 +187,7 @@ - (void)_withShadowViewWithStyle:(void (^)(YGNodeRef node))configBlock
187187
RCTShadowView *view = [self _shadowViewWithConfig:configBlock];
188188
[self.parentView insertReactSubview:view atIndex:0];
189189
view.intrinsicContentSize = contentSize;
190-
[self.parentView layoutWithAffectedShadowViews:[NSHashTable weakObjectsHashTable]];
190+
[self.parentView layoutWithAffectedShadowViews:[NSPointerArray weakObjectsPointerArray]];
191191
CGRect actualRect = [view measureLayoutRelativeToAncestor:self.parentView];
192192
XCTAssertTrue(
193193
CGRectEqualToRect(expectedRect, actualRect),

0 commit comments

Comments
 (0)