Skip to content

Commit e894389

Browse files
authored
Add experimental feature of hierarchyDisplayDidFinish being recursive (#2123)
* Add experimental feature of hierarchyDisplayDidFinish being recursive ## Summary `hierarchyDisplayDidFinish` is currently called when a node's immediate subnodes implement custom CALayer rendering. For example, ASNetworkImageNode and ASTextNode perform this sort of rendering. However, it can be useful -- and less fragile -- if `hierarchyDisplayDidFinish` is propagated further up the node hierarchy. That way, if a feature is refactored such that an extra node appears between the node implementing `hierarchyDisplayDidFinish` and the nodes doing CALayer rendering, we don't lose the callback. ## Test plan Manually tested using a modified version of the Kittens example. Also ran `build.sh tests`. * Revert SDK change since it's still Xcode 15
1 parent 2a5ae7d commit e894389

File tree

5 files changed

+31
-7
lines changed

5 files changed

+31
-7
lines changed

.ruby-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.3.0
1+
3.3.8

Source/ASDisplayNode+Beta.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ typedef struct {
122122
* and other nodes that are ready to do their final display). Each render of every progressive jpeg network node would cause this to be called, so
123123
* this hook could be called up to 1 + (pJPEGcount * pJPEGrenderCount) times. The render count depends on how many times the downloader calls the
124124
* progressImage block.
125+
* @note This is only called when immediate children implement custom CALayer rendering. To propagate beyond immediate supernode, turn on ASExperimentalHierarchyDisplayDidFinishIsRecursive
125126
*/
126127
AS_CATEGORY_IMPLEMENTABLE
127128
- (void)hierarchyDisplayDidFinish NS_REQUIRES_SUPER;

Source/ASDisplayNode.mm

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1318,21 +1318,22 @@ - (BOOL)_implementsDisplay
13181318

13191319
// Track that a node will be displayed as part of the current node hierarchy.
13201320
// The node sending the message should usually be passed as the parameter, similar to the delegation pattern.
1321-
- (void)_pendingNodeWillDisplay:(ASDisplayNode *)node
1321+
- (BOOL)_pendingNodeWillDisplay:(ASDisplayNode *)node
13221322
{
13231323
ASDisplayNodeAssertMainThread();
13241324

13251325
// No lock needed as _pendingDisplayNodes is main thread only
13261326
if (!_pendingDisplayNodes) {
13271327
_pendingDisplayNodes = [[ASWeakSet alloc] init];
13281328
}
1329-
1329+
BOOL wasEmpty = [_pendingDisplayNodes isEmpty];
13301330
[_pendingDisplayNodes addObject:node];
1331+
return wasEmpty;
13311332
}
13321333

13331334
// Notify that a node that was pending display finished
13341335
// The node sending the message should usually be passed as the parameter, similar to the delegation pattern.
1335-
- (void)_pendingNodeDidDisplay:(ASDisplayNode *)node
1336+
- (BOOL)_pendingNodeDidDisplay:(ASDisplayNode *)node
13361337
{
13371338
ASDisplayNodeAssertMainThread();
13381339

@@ -1367,6 +1368,10 @@ - (void)_pendingNodeDidDisplay:(ASDisplayNode *)node
13671368
}
13681369
}
13691370
__instanceLock__.unlock();
1371+
1372+
return YES;
1373+
} else {
1374+
return NO;
13701375
}
13711376
}
13721377

@@ -1768,13 +1773,29 @@ - (void)displayDidFinish
17681773
- (void)subnodeDisplayWillStart:(ASDisplayNode *)subnode
17691774
{
17701775
// Subclass hook
1771-
[self _pendingNodeWillDisplay:subnode];
1776+
BOOL didAddFirstOne = [self _pendingNodeWillDisplay:subnode];
1777+
1778+
if (didAddFirstOne && ASActivateExperimentalFeature(ASExperimentalHierarchyDisplayDidFinishIsRecursive)) {
1779+
__instanceLock__.lock();
1780+
ASDisplayNode *supernode = _supernode;
1781+
__instanceLock__.unlock();
1782+
1783+
[supernode subnodeDisplayWillStart:self];
1784+
}
17721785
}
17731786

17741787
- (void)subnodeDisplayDidFinish:(ASDisplayNode *)subnode
17751788
{
17761789
// Subclass hook
1777-
[self _pendingNodeDidDisplay:subnode];
1790+
BOOL didRemoveLastOne = [self _pendingNodeDidDisplay:subnode];
1791+
1792+
if (didRemoveLastOne && ASActivateExperimentalFeature(ASExperimentalHierarchyDisplayDidFinishIsRecursive)) {
1793+
__instanceLock__.lock();
1794+
ASDisplayNode *supernode = _supernode;
1795+
__instanceLock__.unlock();
1796+
1797+
[supernode subnodeDisplayDidFinish:self];
1798+
}
17781799
}
17791800

17801801
#pragma mark <CALayerDelegate>

Source/ASExperimentalFeatures.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ typedef NS_OPTIONS(NSUInteger, ASExperimentalFeatures) {
3333
ASExperimentalRangeUpdateOnChangesetUpdate = 1 << 12, // exp_range_update_on_changeset_update
3434
ASExperimentalNoTextRendererCache = 1 << 13, // exp_no_text_renderer_cache
3535
ASExperimentalLockTextRendererCache = 1 << 14, // exp_lock_text_renderer_cache
36+
ASExperimentalHierarchyDisplayDidFinishIsRecursive = 1 << 15, // exp_hierarchy_display_did_finish_is_recursive
3637
ASExperimentalFeatureAll = 0xFFFFFFFF
3738
};
3839

Source/ASExperimentalFeatures.mm

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
@"exp_main_thread_only_data_controller",
2727
@"exp_range_update_on_changeset_update",
2828
@"exp_no_text_renderer_cache",
29-
@"exp_lock_text_renderer_cache"]));
29+
@"exp_lock_text_renderer_cache",
30+
@"exp_hierarchy_display_did_finish_is_recursive"]));
3031

3132
if (flags == ASExperimentalFeatureAll) {
3233
return allNames;

0 commit comments

Comments
 (0)