Skip to content
This repository was archived by the owner on Feb 2, 2023. It is now read-only.
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 31 additions & 14 deletions AsyncDisplayKit/ASDisplayNode.mm
Original file line number Diff line number Diff line change
Expand Up @@ -337,9 +337,9 @@ - (id)initWithLayerBlock:(ASDisplayNodeLayerBlock)layerBlock didLoadBlock:(ASDis
- (void)dealloc
{
ASDisplayNodeAssertMainThread();
// Synchronous nodes may not be able to call the hierarchy notifications, so only enforce for regular nodes.
ASDisplayNodeAssert(_flags.synchronous || !ASInterfaceStateIncludesVisible(_interfaceState), @"Node should always be marked invisible before deallocating; interfaceState: %lu, %@", (unsigned long)_interfaceState, self);

self.interfaceState &= ~ASInterfaceStateVisible;

self.asyncLayer.asyncDelegate = nil;
_view.asyncdisplaykit_node = nil;
_layer.asyncdisplaykit_node = nil;
Expand Down Expand Up @@ -829,7 +829,7 @@ - (BOOL)displaysAsynchronously
- (BOOL)_displaysAsynchronously
{
ASDisplayNodeAssertThreadAffinity(self);
return self.isSynchronous == NO && _flags.displaysAsynchronously;
return _flags.synchronous == NO && _flags.displaysAsynchronously;
}

- (void)setDisplaysAsynchronously:(BOOL)displaysAsynchronously
Expand Down Expand Up @@ -1545,10 +1545,11 @@ - (void)__enterHierarchy
// Profiling has shown that locking this method is beneficial, so each of the property accesses don't have to lock and unlock.
ASDN::MutexLocker l(_propertyLock);

if (!self.inHierarchy && !_flags.visibilityNotificationsDisabled && ![self __selfOrParentHasVisibilityNotificationsDisabled]) {
self.inHierarchy = YES;
if (!_flags.isInHierarchy && !_flags.visibilityNotificationsDisabled && ![self __selfOrParentHasVisibilityNotificationsDisabled]) {
_flags.isEnteringHierarchy = YES;
if (self.shouldRasterizeDescendants) {
_flags.isInHierarchy = YES;

if (_flags.shouldRasterizeDescendants) {
// Nodes that are descendants of a rasterized container do not have views or layers, and so cannot receive visibility notifications directly via orderIn/orderOut CALayer actions. Manually send visibility notifications to rasterized descendants.
[self _recursiveWillEnterHierarchy];
} else {
Expand All @@ -1568,7 +1569,7 @@ - (void)__enterHierarchy
[self _setupPlaceholderLayerIfNeeded];
_placeholderLayer.opacity = 1.0;
[CATransaction commit];
[self.layer addSublayer:_placeholderLayer];
[layer addSublayer:_placeholderLayer];
}
}
}
Expand All @@ -1582,18 +1583,34 @@ - (void)__exitHierarchy
// Profiling has shown that locking this method is beneficial, so each of the property accesses don't have to lock and unlock.
ASDN::MutexLocker l(_propertyLock);

if (self.inHierarchy && !_flags.visibilityNotificationsDisabled && ![self __selfOrParentHasVisibilityNotificationsDisabled]) {
self.inHierarchy = NO;
if (_flags.isInHierarchy && !_flags.visibilityNotificationsDisabled && ![self __selfOrParentHasVisibilityNotificationsDisabled]) {
_flags.isExitingHierarchy = YES;
_flags.isInHierarchy = NO;

[self.asyncLayer cancelAsyncDisplay];

_flags.isExitingHierarchy = YES;
if (self.shouldRasterizeDescendants) {
if (_flags.shouldRasterizeDescendants) {
// Nodes that are descendants of a rasterized container do not have views or layers, and so cannot receive visibility notifications directly via orderIn/orderOut CALayer actions. Manually send visibility notifications to rasterized descendants.
[self _recursiveDidExitHierarchy];
} else {
[self didExitHierarchy];
}

// This case is important when tearing down hierarchies. We must deliver a visibilityDidChange:NO callback, as part our API guarantee that this method can be used for
// things like data analytics about user content viewing. We cannot call the method in the dealloc as any incidental retain operations in client code would fail.
// Additionally, it may be that a Standard UIView which is containing us is moving between hierarchies, and we should not send the call if we will be re-added in the
// same runloop. Strategy: strong reference (might be the last!), wait one runloop, and confirm we are still outside the hierarchy (both layer-backed and view-backed).
// TODO: This approach could be optimized by only performing the dispatch for root elements + recursively apply the interface state change. This would require a closer
// integration with _ASDisplayLayer to ensure that the superlayer pointer has been cleared by this stage (to check if we are root or not), or a different delegate call.

if (ASInterfaceStateIncludesVisible(_interfaceState)) {
dispatch_async(dispatch_get_main_queue(), ^{
ASDN::MutexLocker l(_propertyLock);
if (!_flags.isInHierarchy && ASInterfaceStateIncludesVisible(_interfaceState)) {
self.interfaceState = (_interfaceState & ~ASInterfaceStateVisible);
}
});
}

[self didExitHierarchy];
_flags.isExitingHierarchy = NO;
}
}
Expand Down Expand Up @@ -1719,7 +1736,7 @@ - (void)_pendingNodeDidDisplay:(ASDisplayNode *)node
// Helper method to summarize whether or not the node run through the display process
- (BOOL)__implementsDisplay
{
return _flags.implementsDrawRect || _flags.implementsImageDisplay || self.shouldRasterizeDescendants || _flags.implementsInstanceDrawRect || _flags.implementsInstanceImageDisplay;
return _flags.implementsDrawRect || _flags.implementsImageDisplay || _flags.shouldRasterizeDescendants || _flags.implementsInstanceDrawRect || _flags.implementsInstanceImageDisplay;
}

- (BOOL)placeholderShouldPersist
Expand Down