diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index facba9f6b9..42c4bf79a9 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -1770,6 +1770,10 @@ static BOOL ShouldUseNewRenderingRange = NO; // Trigger asynchronous measurement if it is not already cached or being calculated. } + // For the FetchData and Display ranges, we don't want to call -clear* if not being managed by a range controller. + // Otherwise we get flashing behavior from normal UIKit manipulations like navigation controller push / pop. + // Still, the interfaceState should be updated to the current state of the node; just don't act on the transition. + // Entered or exited data loading state. if ((newState & ASInterfaceStateFetchData) != (oldState & ASInterfaceStateFetchData)) { if (newState & ASInterfaceStateFetchData) { diff --git a/AsyncDisplayKitTests/ASDisplayNodeTests.m b/AsyncDisplayKitTests/ASDisplayNodeTests.m index 4c45aeadba..e343e115b3 100644 --- a/AsyncDisplayKitTests/ASDisplayNodeTests.m +++ b/AsyncDisplayKitTests/ASDisplayNodeTests.m @@ -1702,7 +1702,11 @@ static inline BOOL _CGPointEqualToPointWithEpsilon(CGPoint point1, CGPoint point XCTAssert(node.interfaceState == ASInterfaceStateInHierarchy); [node.view removeFromSuperview]; - XCTAssert(!node.hasFetchedData); + // We don't want to call -clearFetchedData on nodes that aren't being managed by a range controller. + // Otherwise we get flashing behavior from normal UIKit manipulations like navigation controller push / pop. + // Still, the interfaceState should be None to reflect the current state of the node. + // We just don't proactively clear contents or fetched data for this state transition. + XCTAssert(node.hasFetchedData); XCTAssert(node.interfaceState == ASInterfaceStateNone); }