Skip to content
This repository was archived by the owner on Feb 2, 2023. It is now read-only.

Commit 92126f0

Browse files
author
Scott Goodson
committed
Support surprisingly nice automatic behavior for the unsupported case of view-backed nodes as children of layer-backed ones.
1 parent bbc0452 commit 92126f0

3 files changed

Lines changed: 36 additions & 12 deletions

File tree

AsyncDisplayKit/ASDisplayNode.mm

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -996,13 +996,14 @@ - (void)_insertSubnode:(ASDisplayNode *)subnode atSubnodeIndex:(NSInteger)subnod
996996
if (isMovingEquivalentParents) {
997997
[subnode __incrementVisibilityNotificationsDisabled];
998998
}
999+
9991000
[subnode removeFromSupernode];
1000-
1001+
[oldSubnode removeFromSupernode];
1002+
10011003
if (!_subnodes)
10021004
_subnodes = [[NSMutableArray alloc] init];
1003-
1004-
[oldSubnode removeFromSupernode];
10051005
[_subnodes insertObject:subnode atIndex:subnodeIndex];
1006+
[subnode __setSupernode:self];
10061007

10071008
// Don't bother inserting the view/layer if in a rasterized subtree, because there are no layers in the hierarchy and none of this could possibly work.
10081009
if (!_flags.shouldRasterizeDescendants && [self __shouldLoadViewOrLayer]) {
@@ -1030,8 +1031,6 @@ - (void)_insertSubnode:(ASDisplayNode *)subnode atSubnodeIndex:(NSInteger)subnod
10301031
if (isMovingEquivalentParents) {
10311032
[subnode __decrementVisibilityNotificationsDisabled];
10321033
}
1033-
1034-
[subnode __setSupernode:self];
10351034
}
10361035

10371036
- (void)replaceSubnode:(ASDisplayNode *)oldSubnode withSubnode:(ASDisplayNode *)replacementSubnode
@@ -1231,7 +1230,7 @@ - (void)removeFromSupernode
12311230
BOOL shouldRemoveFromSuperviewOrSuperlayer = NO;
12321231

12331232
if (self.nodeLoaded && _supernode.nodeLoaded) {
1234-
if (_flags.layerBacked) {
1233+
if (_flags.layerBacked || _supernode.layerBacked) {
12351234
shouldRemoveFromSuperviewOrSuperlayer = (_layer.superlayer == _supernode.layer);
12361235
} else {
12371236
shouldRemoveFromSuperviewOrSuperlayer = (_view.superview == _supernode.view);

AsyncDisplayKit/Details/_ASDisplayView.mm

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,17 @@ - (void)willMoveToSuperview:(UIView *)newSuperview
101101
BOOL needsSupernodeUpdate = NO;
102102

103103
if (supernode) {
104-
// If we have a supernode, compensate for users directly messing with views by updating to any new supernode.
105-
needsSupernodeUpdate = (!supernodeLoaded || supernode.view != newSuperview);
104+
if (supernodeLoaded) {
105+
if (supernode.layerBacked) {
106+
// See comment in -didMoveToSuperview. This case should be avoided, but is possible with app-level coding errors.
107+
needsSupernodeUpdate = (supernode.layer != newSuperview.layer);
108+
} else {
109+
// If we have a supernode, compensate for users directly messing with views by hitching up to any new supernode.
110+
needsSupernodeUpdate = (supernode.view != newSuperview);
111+
}
112+
} else {
113+
needsSupernodeUpdate = YES;
114+
}
106115
} else {
107116
// If we have no supernode and we are now in a view hierarchy, check to see if we can hook up to a supernode.
108117
needsSupernodeUpdate = (newSuperview != nil);
@@ -129,11 +138,23 @@ - (void)didMoveToSuperview
129138

130139
if (superview) {
131140
// If our new superview is not the same as the supernode's view, or the supernode has no view, disconnect.
132-
needsSupernodeRemoval = (!supernodeLoaded || supernode.view != superview);
141+
if (supernodeLoaded) {
142+
if (supernode.layerBacked) {
143+
// As asserted at the top, this shouldn't be possible, but in production with assertions disabled it can happen.
144+
// We try to make such code behave as well as feasible because it's not that hard of an error to make if some deep
145+
// child node of a layer-backed node happens to be view-backed, but it is not supported and should be avoided.
146+
needsSupernodeRemoval = (supernode.layer != superview.layer);
147+
} else {
148+
needsSupernodeRemoval = (supernode.view != superview);
149+
}
150+
} else {
151+
needsSupernodeRemoval = YES;
152+
}
133153
} else {
134154
// If supernode is loaded but our superview is nil, the user manually removed us, so disconnect supernode.
135155
needsSupernodeRemoval = supernodeLoaded;
136156
}
157+
137158
if (needsSupernodeRemoval) {
138159
// The node will only disconnect from its supernode, not removeFromSuperview, in this condition.
139160
[_node removeFromSupernode];

AsyncDisplayKitTests/ASDisplayNodeTests.m

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,16 +1342,20 @@ - (void)testInsertSubviewAtIndexWithMeddlingViewsAndLayersViewBacked
13421342
[parent insertSubnode:c belowSubnode:b];
13431343
XCTAssertEqualObjects(orderStringFromSublayers(parent.layer), @"a,e,d,c,b", @"Didn't match");
13441344

1345-
XCTAssertEqual(3u, parent.subnodes.count, @"Should have the right subnode count");
1345+
XCTAssertEqual(4u, parent.subnodes.count, @"Should have the right subnode count");
13461346
XCTAssertEqual(4u, parent.view.subviews.count, @"Should have the right subview count");
13471347
XCTAssertEqual(5u, parent.layer.sublayers.count, @"Should have the right sublayer count");
1348+
1349+
[e removeFromSuperlayer];
1350+
XCTAssertEqual(4u, parent.layer.sublayers.count, @"Should have the right sublayer count");
13481351

13491352
//TODO: assert that things deallocate immediately and don't have latent autoreleases in here
13501353
[parent release];
13511354
[a release];
13521355
[b release];
13531356
[c release];
13541357
[d release];
1358+
[e release];
13551359
}
13561360

13571361
- (void)testAppleBugInsertSubview
@@ -1415,11 +1419,11 @@ - (void)testInsertSubviewAtIndexWithMeddlingView
14151419
[parent.view insertSubview:d aboveSubview:a.view];
14161420
XCTAssertEqualObjects(orderStringFromSublayers(parent.layer), @"a,d,b", @"Didn't match");
14171421

1418-
// (a,e,d,b) => (a,d,>c<,b)
1422+
// (a,d,b) => (a,d,>c<,b)
14191423
[parent insertSubnode:c belowSubnode:b];
14201424
XCTAssertEqualObjects(orderStringFromSublayers(parent.layer), @"a,d,c,b", @"Didn't match");
14211425

1422-
XCTAssertEqual(3u, parent.subnodes.count, @"Should have the right subnode count");
1426+
XCTAssertEqual(4u, parent.subnodes.count, @"Should have the right subnode count");
14231427
XCTAssertEqual(4u, parent.view.subviews.count, @"Should have the right subview count");
14241428
XCTAssertEqual(4u, parent.layer.sublayers.count, @"Should have the right sublayer count");
14251429

0 commit comments

Comments
 (0)